294 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			294 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
.NH
 | 
						|
What lint checks
 | 
						|
.NH 2
 | 
						|
Set, used and unused variables
 | 
						|
.PP
 | 
						|
We make a distinction between two classes of variables:
 | 
						|
the class of automatic variables (including register variables)
 | 
						|
and the other variables.
 | 
						|
The other variables, global variables, static variables, formal
 | 
						|
parameters et cetera, are assumed to have a defined value.
 | 
						|
Global variables e.g., are initialized by the compiled code at
 | 
						|
zeros; formal parameters have a value which is equal to the value
 | 
						|
of the corresponding actual parameter.
 | 
						|
These variables can be used without explicitly initializing them.
 | 
						|
The initial value of automatic variables is undefined (if they are
 | 
						|
not initialized at declaration).
 | 
						|
These variables should be set before they are used.
 | 
						|
A variable is set by
 | 
						|
.IP
 | 
						|
.RS
 | 
						|
.IP 1.
 | 
						|
an assignment (including an initialization)
 | 
						|
.IP 2.
 | 
						|
taking the address
 | 
						|
.RE
 | 
						|
.PP
 | 
						|
The first case is clear. The second case is plausible.
 | 
						|
It would take to much effort (if at all possible) to check
 | 
						|
if a variable is set through one of its aliases.
 | 
						|
Because
 | 
						|
.I lint
 | 
						|
should not warn about correct constructs, it does this conservative
 | 
						|
approach.
 | 
						|
Structures (and unions) can also be set by setting at
 | 
						|
least one member.
 | 
						|
Again a conservative approach.
 | 
						|
An array can be set by using its name (e.g. as actual parameter
 | 
						|
of a function call).
 | 
						|
.I Lint
 | 
						|
warns for usage as
 | 
						|
.I rvalue
 | 
						|
of automatic variables which are not set.
 | 
						|
.PP
 | 
						|
A variable is used if
 | 
						|
.IP
 | 
						|
.RS
 | 
						|
.IP 1.
 | 
						|
it is used as a
 | 
						|
.I rvalue
 | 
						|
.IP 2
 | 
						|
its address is taken
 | 
						|
.IP
 | 
						|
Arrays and structures (and unions) are also used if one entry
 | 
						|
or one member respectively is used.
 | 
						|
.RE
 | 
						|
.PP
 | 
						|
When a variable is never used in the part of the program where it is
 | 
						|
visible, a warning is given.
 | 
						|
For variables declared at the beginning of a compound statement,
 | 
						|
a check is made at the end of this statement.
 | 
						|
For formal parameters a check is made at the end of the function
 | 
						|
definition.
 | 
						|
At the end of a file this is done for global static definitions.
 | 
						|
For external variables a warning can be given when all the files
 | 
						|
are parsed.
 | 
						|
.NH 2
 | 
						|
Flow of control
 | 
						|
.PP
 | 
						|
The way
 | 
						|
.I lint
 | 
						|
keeps track of the flow of control is best explained by means of
 | 
						|
an example.
 | 
						|
See the program of figure 1.
 | 
						|
.KF
 | 
						|
.DS B
 | 
						|
.ft CW
 | 
						|
if (cond)
 | 
						|
	/* a statement which is executed if cond is true,
 | 
						|
	 * the if-part
 | 
						|
	 */
 | 
						|
else
 | 
						|
	/* the else-part */
 | 
						|
.DE
 | 
						|
.br
 | 
						|
.ce
 | 
						|
.I
 | 
						|
figure\ 1.
 | 
						|
.R
 | 
						|
.KE
 | 
						|
.PP
 | 
						|
After evaluation of \f(CWcond\fP, two things can happen.
 | 
						|
The if-part is executed or the else-part is executed (but not both).
 | 
						|
Variables which are set in the if-part but not in the else-part,
 | 
						|
need not be set after the if statement, and vice versa.
 | 
						|
.I Lint
 | 
						|
detects this and assumes these variables after the if statement to
 | 
						|
be \fImaybe set\fR.
 | 
						|
(See figure 2.)
 | 
						|
.KF
 | 
						|
.DS B
 | 
						|
.ft CW
 | 
						|
int cond;
 | 
						|
 | 
						|
main()
 | 
						|
{
 | 
						|
        int i, j;
 | 
						|
 | 
						|
        if (cond) {
 | 
						|
                i = 0;
 | 
						|
                j = 0;
 | 
						|
        }
 | 
						|
        else
 | 
						|
                use(i);  /* i may be used before set */
 | 
						|
        use(j);          /* maybe j used before set  */
 | 
						|
}
 | 
						|
.DE
 | 
						|
.br
 | 
						|
.ce
 | 
						|
.I
 | 
						|
figure 2.
 | 
						|
.R
 | 
						|
.KE
 | 
						|
.PP
 | 
						|
If both the if-part and the else-part are never left (i.e. they
 | 
						|
contain an endless loop or a return statement),
 | 
						|
.I lint
 | 
						|
knows that the if statement is never left too.
 | 
						|
Besides the if statement,
 | 
						|
.I lint
 | 
						|
knows the possible flows of control in while, do, for and
 | 
						|
switch statements.
 | 
						|
It also detects some endless loops like \f(CWwhile(1)\fP,
 | 
						|
\f(CWdo ... while (1)\fP, \f(CWfor (;;)\fP.
 | 
						|
.NH 2
 | 
						|
Functions
 | 
						|
.PP
 | 
						|
Most C compilers will not complain if a function is called with actual
 | 
						|
parameters of a different type than the function expects.
 | 
						|
Using a function in one file as a function of
 | 
						|
type
 | 
						|
.I A
 | 
						|
while defining it in another file as a function of type
 | 
						|
.I B
 | 
						|
is also allowed by most compilers.
 | 
						|
It needs no explanation that this can lead to serious trouble.
 | 
						|
.PP
 | 
						|
.I Lint
 | 
						|
checks if functions are called with the correct number of arguments,
 | 
						|
if the types of the actual parameters correspond with the types of
 | 
						|
the formal parameters and if function values are used in a way
 | 
						|
consistently with their declaration.
 | 
						|
When the result of a function is used, a check is made to see if
 | 
						|
the function returns a value.
 | 
						|
When a function returns a value,
 | 
						|
.I lint
 | 
						|
checks if the values of all calls of this function are used.
 | 
						|
.NH 2
 | 
						|
Undefined evaluation order
 | 
						|
.PP
 | 
						|
The semantics of C do not define evaluation orders for some
 | 
						|
constructs, which, at first sight, seem well defined.
 | 
						|
The evaluation order of the expression
 | 
						|
.ft CW
 | 
						|
a[i]\ =\ i++;
 | 
						|
.R
 | 
						|
e.g., is undefined.
 | 
						|
It can be translated to something with the semantics of
 | 
						|
.ft CW
 | 
						|
a[i]\ =\ i; i++;
 | 
						|
.R
 | 
						|
which is what probably was meant, or
 | 
						|
.ft CW
 | 
						|
a[i+1]\ =\ i; i++;.
 | 
						|
.R
 | 
						|
An easier example to explain why, is
 | 
						|
.ft CW
 | 
						|
j\ =\ a[i]\ +\ i++;.
 | 
						|
.R
 | 
						|
`\f(CW+\fR' Is a so called
 | 
						|
.I commutative
 | 
						|
operator (with respect to the evaluation order) , as is `\f(CW=\fR'.
 | 
						|
This allows the compiler to choose which term to evaluate first.
 | 
						|
It is easy to see, that it makes a difference for the value of
 | 
						|
.ft CW
 | 
						|
j,
 | 
						|
.R
 | 
						|
which order is chosen.
 | 
						|
The expression
 | 
						|
.ft CW
 | 
						|
i++
 | 
						|
.R
 | 
						|
is said to have
 | 
						|
.I
 | 
						|
side effects.
 | 
						|
.R
 | 
						|
It affects the value of
 | 
						|
.ft CW
 | 
						|
i.
 | 
						|
.R
 | 
						|
Because this value is used in the other term, this gives a conflict.
 | 
						|
.PP
 | 
						|
A function call with reference to a variable as argument can have
 | 
						|
side effects to.
 | 
						|
Therefor, the evaluation order of
 | 
						|
.ft CW
 | 
						|
i
 | 
						|
.R
 | 
						|
in the expression
 | 
						|
.ft CW
 | 
						|
f(&i)\ +\ i
 | 
						|
.R
 | 
						|
is undefined.
 | 
						|
When a function is called with an array as argument, this array
 | 
						|
can be affected by the function, because only the address of the
 | 
						|
array is passed to the function.
 | 
						|
(In Pascal a copy of the array is passed to the function if the
 | 
						|
formal parameter is not declared \fIvar\fP.)
 | 
						|
So the evaluation order of
 | 
						|
.ft CW
 | 
						|
a
 | 
						|
.R
 | 
						|
in the expression
 | 
						|
.ft CW
 | 
						|
f(a)\ +\ a[0]
 | 
						|
.R
 | 
						|
is undefined.
 | 
						|
This one is not yet detected by
 | 
						|
.I lint.
 | 
						|
.PP
 | 
						|
Global variables can still cause trouble.
 | 
						|
If function
 | 
						|
.ft CW
 | 
						|
f
 | 
						|
.R
 | 
						|
affects the global variable
 | 
						|
.ft CW
 | 
						|
i,
 | 
						|
.R
 | 
						|
the value of the expression
 | 
						|
.ft CW
 | 
						|
f()\ +\ i
 | 
						|
.R
 | 
						|
is undefined, because the evaluation order of \f(CWi\fP is undefined.
 | 
						|
.PP
 | 
						|
The evaluation order of the arguments of a function is not
 | 
						|
defined, so the expression
 | 
						|
.ft CW
 | 
						|
f(i,\ i++)
 | 
						|
.R
 | 
						|
gives a warning
 | 
						|
.ft CW
 | 
						|
i evaluation order undefined.
 | 
						|
.R
 | 
						|
.NH 2
 | 
						|
Pointer alignment problems
 | 
						|
.PP
 | 
						|
For pointers to objects of different types there are different
 | 
						|
alignment restrictions.
 | 
						|
On some machines pointers to type char can have both odd and even
 | 
						|
values, whereas pointers to type int should contain an even address.
 | 
						|
.I Lint
 | 
						|
could warn for all pointer conversions.
 | 
						|
This is not what
 | 
						|
.I lint
 | 
						|
does.
 | 
						|
.I Lint
 | 
						|
assumes that some pointers are more restricted than others, and
 | 
						|
that pointers of some types can safely be converted to a pointer
 | 
						|
of a less restrictive type.
 | 
						|
The order of restriction is as follows (`\(<=' means
 | 
						|
`is not more restricted than') :
 | 
						|
.PP
 | 
						|
.ce
 | 
						|
char \(<= short \(<= int \(<= long
 | 
						|
.ce
 | 
						|
float \(<= double
 | 
						|
.NH 2
 | 
						|
Libraries
 | 
						|
.PP
 | 
						|
C is a small language.
 | 
						|
As a matter of fact it has no i/o routines.
 | 
						|
To make it a useful language, C is supported by libraries.
 | 
						|
These libraries contain functions and variables that can be used by any
 | 
						|
C program.
 | 
						|
.I Lint
 | 
						|
knows some libraries too.
 | 
						|
At this moment it knows the `-\fIlc\fR', `-\fIlm\fR' and
 | 
						|
`-\fIlcurses\fR' libraries.
 | 
						|
The `-\fIlc\fR' library, containing definitions for functions from
 | 
						|
chapter two and three of the \s-2UNIX\s+2 programmers manual, is default.
 | 
						|
.I Lint
 | 
						|
warns for definitions of functions or global variables with the
 | 
						|
same name as a function definition in a library.
 | 
						|
.bp
 |