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
 |