295 lines
7.1 KiB
Plaintext
295 lines
7.1 KiB
Plaintext
|
.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
|