Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – tendra.SVN – Blame – /branches/tendra4/doc/tdfc/tdfc8.html – Rev 2

Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
<!-- Crown Copyright (c) 1998 -->
2
<HTML>
3
<HEAD>
4
<TITLE>C Checker Reference Manual: Data Flow and Variable Analysis</TITLE>
5
</HEAD>
6
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#400080" ALINK="#FF0000">
7
<A NAME=S42>
8
<H1>C Checker Reference Manual</H1>
9
<H3>January 1998</H3>
10
<A HREF="tdfc9.html"><IMG SRC="../images/next.gif" ALT="next section"></A>
11
<A HREF="tdfc7.html"><IMG SRC="../images/prev.gif" ALT="previous section"></A>
12
<A HREF="tdfc1.html"><IMG SRC="../images/top.gif" ALT="current document"></A>
13
<A HREF="../index.html"><IMG SRC="../images/home.gif" ALT="TenDRA home page">
14
</A>
15
<IMG SRC="../images/no_index.gif" ALT="document index"><P>
16
<HR>
17
<DL>
18
<DT><A HREF="#S43"><B>5.1 </B> - Introduction</A><DD>
19
<DT><A HREF="#S44"><B>5.2 </B> - Unreachable code analysis</A><DD>
20
<DT><A HREF="#S45"><B>5.3 </B> - Case fall through</A><DD>
21
<DT><A HREF="#S46"><B>5.4 </B> - Unusual flow in conditional statements</A><DD>
22
<DL>
23
<DT><A HREF="#S47"><B>5.4.1 </B> - Empty if statements</A><DD>
24
<DT><A HREF="#S48"><B>5.4.2 </B> - Use of assignments as control expressions</A>
25
<DD>
26
<DT><A HREF="#S49"><B>5.4.3 </B> - Constant control expressions</A><DD>
27
</DL>
28
<DT><A HREF="#S50"><B>5.5 </B> - Operator precedence</A><DD>
29
<DT><A HREF="#S51"><B>5.6 </B> - Variable analysis</A><DD>
30
<DL>
31
<DT><A HREF="#S52"><B>5.6.1 </B> - Order of evaluation</A><DD>
32
<DT><A HREF="#S53"><B>5.6.2 </B> - Modification between sequence points</A><DD>
33
<DT><A HREF="#S54"><B>5.6.3 </B> - Operand of sizeof operator</A><DD>
34
<DT><A HREF="#S55"><B>5.6.4 </B> - Unused variables</A><DD>
35
<DT><A HREF="#S56"><B>5.6.5 </B> - Values set and not used</A><DD>
36
<DT><A HREF="#S57"><B>5.6.6 </B> - Variable which has not been set
37
is used</A><DD>
38
</DL>
39
<DT><A HREF="#S58"><B>5.7 </B> - Overriding the variable analysis</A><DD>
40
<DL>
41
<DT><A HREF="#S59"><B>5.7.1 </B> - Discarding variables</A><DD>
42
<DT><A HREF="#S60"><B>5.7.2 </B> - Setting variables</A><DD>
43
<DT><A HREF="#S61"><B>5.7.3 </B> - Exhaustive switch statements</A><DD>
44
<DT><A HREF="#S62"><B>5.7.4 </B> - Non-returning functions</A><DD>
45
</DL>
46
<DT><A HREF="#S63"><B>5.8 </B> - Discard Analysis</A><DD>
47
<DL>
48
<DT><A HREF="#S64"><B>5.8.1 </B> - Discarded function returns</A><DD>
49
<DT><A HREF="#S65"><B>5.8.2 </B> - Discarded computed values</A><DD>
50
<DT><A HREF="#S66"><B>5.8.3 </B> - Unused static variables and procedures</A>
51
<DD>
52
</DL>
53
<DT><A HREF="#S67"><B>5.9 </B> - Overriding the discard analysis</A><DD>
54
<DL>
55
<DT><A HREF="#S68"><B>5.9.1 </B> - Discarding function returns and
56
computed values</A><DD>
57
<DT><A HREF="#S69"><B>5.9.2 </B> - Preserving unused statics</A><DD>
58
</DL>
59
</DL>
60
 
61
<HR>
62
<H1>5  Data Flow and Variable Analysis</H1>
63
<A NAME=S43>
64
<HR><H2>5.1  Introduction</H2>
65
The checker has a number of features which can be used to help track
66
down potential programming errors relating to the use of variables
67
within a source file and the flow of control through the program.
68
Examples of this are detecting sections of unused code, flagging expressions
69
that depend upon the order of evaluation where the order is not defined,
70
checking for unused static variables, etc.<P>
71
<A NAME=S44>
72
<HR><H2>5.2  <A NAME=2>Unreachable code analysis</H2>
73
Consider the following function definition:<P>
74
<PRE>
75
	int f ( int n )
76
	{
77
		if ( n ) {
78
			return ( 1 );
79
		} else {
80
			return ( 0 );
81
		}
82
		return ( 2 );
83
	}
84
</PRE>
85
The final return statement is redundant since it can never be reached.
86
The test for unreachable code is controlled by:<P>
87
<PRE>
88
	#pragma TenDRA unreachable code <EM>permit</EM>
89
</PRE>
90
where permit is replaced by <CODE>disallow</CODE> to give an error
91
if unreached code is detected, <CODE>warning</CODE> to give a warning,
92
or <CODE>allow</CODE> to disable the test (this is the default).<P>
93
There are also equivalent command-line options to tchk of the form
94
<CODE>-X:unreached=</CODE><CODE>state</CODE>, where <CODE>state</CODE>
95
can be <CODE>check</CODE>, <CODE>warn</CODE> or <CODE>dont</CODE>.<P>
96
Annotations to the code in the form of user-defined keywords may be
97
used to indicate that a certain statement is genuinely reached or
98
unreached. These keywords are introduced using:<P>
99
<PRE>
100
	#pragma TenDRA keyword REACHED for set reachable
101
	#pragma TenDRA keyword UNREACHED for set unreachable
102
</PRE>
103
The statement REACHED then indicates that this portion of the program
104
is actually reachable, whereas UNREACHED indicates that it is unreachable.
105
For example, one way of fixing the program above might be to say that
106
the final return is reachable (this is a blatant lie, but never mind).
107
This would be done as follows:<P>
108
<PRE>
109
	int f ( int n ) {
110
		if ( n ) {
111
			return ( 1 );
112
	} else {
113
			return ( 0 )
114
		}
115
		REACHED
116
		return ( 2 );
117
	}
118
</PRE>
119
An example of the use of UNREACHED might be in the function below
120
which falls out of the bottom without a return statement. We might
121
know that, because it is never called with c equal to zero, the end
122
of the function is never reached. This could be indicated as follows:<P>
123
<PRE>
124
	int f ( int c ){
125
		if ( c ) return ( 1 );
126
		UNREACHED
127
	}
128
</PRE>
129
As always, if new keywords are introduced into a program then definitions
130
need to be provided for <BR>
131
conventional compilers. In this case, this can be done as follows:<P>
132
<PRE>
133
	#ifdef __TenDRA__
134
	#pragma TenDRA keyword REACHED for set reachable
135
	#pragma TenDRA keyword UNREACHED for set unreachable
136
	#else
137
	#define REACHED
138
	#define UNREACHED
139
	#endif
140
</PRE>
141
<A NAME=S45>
142
<HR><H2>5.3  <A NAME=6>Case fall through</H2>
143
Another flow analysis check concerns fall through in case statements.
144
For example, in:<P>
145
<PRE>
146
	void f ( int n )
147
	{
148
		switch ( n ) {
149
			case 1 : puts ( &quot;one&quot; );
150
			case 2 : puts ( &quot;two&quot; );
151
		}
152
	}
153
</PRE>
154
the control falls through from the first case to the second. This
155
may be due to an error in the program (a missing break statement),
156
or be deliberate. Even in the latter case, the code is not particularly
157
maintainable as it stands - there is always the risk when adding a
158
new case that it will interrupt this carefully contrived flow. Thus
159
it is customary to comment all case fall throughs to serve as a warning.<P>
160
In the default mode, the TenDRA C checker ignores all such fall throughs.
161
A check to detect fall through in case statements is controlled by:<P>
162
<PRE>
163
	#pragma TenDRA fall into case <EM>permit</EM>
164
</PRE>
165
where <CODE>permit</CODE> is <CODE>allow</CODE> (no errors), <CODE>warning
166
</CODE> (warn about case fall through) or <CODE>disallow</CODE> (raise
167
errors for case fall through).<P>
168
There are also equivalent command-line options to tcc of the form
169
-<CODE>X:fall_thru=</CODE><CODE>state</CODE>, where <CODE>state</CODE>
170
can be <CODE>check</CODE>, <CODE>warn</CODE> or <CODE>dont</CODE>.<P>
171
Deliberate case fall throughs can be indicated by means of a keyword,
172
which has been introduced using:<P>
173
<PRE>
174
	#pragma TenDRA keyword FALL_THROUGH for fall into case
175
</PRE>
176
Then, if the example above were deliberate, this could be indicated
177
by:<P>
178
<PRE>
179
	void f ( int n ){
180
		switch ( n ) {
181
			case 1 : puts ( &quot;one&quot; );
182
			FALL_THROUGH
183
			case 2 : puts ( &quot;two&quot; );
184
		}
185
	}
186
</PRE>
187
Note that FALL_THROUGH is inserted between the two cases, rather than
188
at the end of the list of statements following the first case.<P>
189
If a keyword is introduced in this way, then an alternative definition
190
needs to be introduced for conventional compilers. This might be done
191
as follows:<P>
192
<PRE>
193
	#ifdef __TenDRA__
194
	#pragma TenDRA keyword FALL_THROUGH for fall into case
195
	#else
196
	#define FALL_THROUGH
197
	#endif
198
</PRE>
199
<A NAME=S46>
200
<HR><H2>5.4  Unusual flow in conditional statements</H2>
201
The following three checks are designed to detect possible errors
202
in conditional statements. <P>
203
<A NAME=S47>
204
<H3>5.4.1  <A NAME=9>Empty if statements</H3>
205
Consider the following C statements:<P>
206
<PRE>
207
	if( var1 == 1 ) ;
208
	var2 = 0 ;
209
</PRE>
210
The conditional statement serves no purpose here and the second statement
211
will always be executed regardless of the value of var1. This is almost
212
certainly not what the programmer intended to write. A test for if
213
statements with no body is controlled by:<P>
214
<PRE>
215
	#pragma TenDRA extra ; after conditional <EM>permit</EM>
216
</PRE>
217
with the usual <CODE>allow</CODE> (this is the default setting), <CODE>warning
218
</CODE> and <CODE>disallow</CODE> options for <EM>permit</EM>.<P>
219
<A NAME=S48>
220
<H3>5.4.2  <A NAME=11>Use of assignments as control expressions</H3>
221
Using the C assignment operator, `=', when the equality operator `=='
222
was intended is an extremely common problem. The pragma:<P>
223
<PRE>
224
	#pragma TenDRA assignment as bool <EM>permit</EM>
225
</PRE>
226
is used to control the treatment of assignments used as the controlling
227
expression of a conditional statement or a loop, e.g.<P>
228
<PRE>
229
	if( var = 1 ) { ...
230
</PRE>
231
The options for <EM>permit</EM> are <CODE>allow</CODE>, <CODE>warning</CODE>
232
and <CODE>disallow</CODE>. The default setting allows assignments
233
to be used as control statements without raising an error.<P>
234
<A NAME=S49>
235
<H3>5.4.3  <A NAME=13>Constant control expressions 
236
</H3>
237
Statements with constant control expressions are not really conditional
238
at all since the value of the control statement can be evaluated statically.
239
Although this feature is sometimes used in loops, relying on a break,
240
goto or return statement to end the loop, it may be useful to detect
241
all constant control expressions to check that they are deliberate.
242
The check for statically constant control expressions is controlled
243
using:<P>
244
<PRE>
245
	#pragma TenDRA const conditional <EM>permit</EM>
246
</PRE>
247
where permit may be replaced by <CODE>disallow</CODE> to give an error
248
when constant control expressions are encountered, <CODE>warning </CODE><EM>to
249
replace the error by a warning,</EM><CODE> </CODE>or the check may
250
be switched off using the <CODE>allow</CODE> (this is the default).<P>
251
<A NAME=S50>
252
<HR><H2>5.5  <A NAME=15>Operator precedence</H2>
253
The ISO C standard section 6.3, provides a set of rules governing
254
the order in which operators within expressions should be applied.
255
These rules are said to specify the operator precedence and are summarised
256
in the table over the page. Operators on the same line have the same
257
precedence and the rows are in order of decreasing precedence. Note
258
that the unary +, -, * and &amp; operators have higher precedence
259
than the binary forms and thus appear higher in the table.<P>
260
The precedence of operators is not always intuitive and often leads
261
to unexpected results when expressions are evaluated. A particularly
262
common example is to write:<P>
263
<PRE>
264
	if ( var &amp; TEST == 1) { ...
265
	}
266
	else { ...
267
</PRE>
268
assuming that the control expression will be evaluated as:<P>
269
<PRE>
270
	( ( var &amp; TEST ) == 1 )
271
</PRE>
272
However, the == operator has a higher precedence than the bitwise
273
&amp; operator and the control expression is evaluated as:<P>
274
<PRE>
275
	( var &amp; ( TEST == 1 ) )
276
</PRE>
277
which in general will give a different result<P>
278
.<BR><IMG SRC="table4.gif"><BR>
279
<P>
280
The TenDRA C checker can be configured to flag expressions containing
281
certain operators whose precedence is commonly confused, namely:<P>
282
<UL>
283
<LI>&amp;&amp; <EM>versus</EM> ||<P>
284
<LI>&lt;&lt; <EM>and</EM> &gt;&gt; <EM>versus</EM> + <EM>and</EM>
285
-<P>
286
<LI>&amp; <EM>versus</EM> == != &lt; &gt; &lt;= &gt;= + <EM>and</EM>
287
-<P>
288
<LI>^ <EM>versus</EM> &amp; == |= &lt; &gt; &lt;= &gt;= + <EM>and</EM>
289
-<P>
290
<LI>| <EM>versus</EM> ^ &amp; == |= &lt; &gt; &lt;= &gt;= + <EM>and</EM>
291
-<P>
292
</UL>
293
The check is switched off by default and is controlled using:<P>
294
<PRE>
295
	#pragma TenDRA operator precedence <EM>status</EM>
296
</PRE>
297
where <EM>status</EM> is <CODE>on</CODE>, <CODE>warning</CODE> or
298
<CODE>off</CODE>.<P>
299
<A NAME=S51>
300
<HR><H2>5.6  Variable analysis</H2>
301
The variable analysis checks are controlled by:<P>
302
<PRE>
303
	#pragma TenDRA variable analysis status
304
</PRE>
305
where <CODE>status</CODE> is <CODE>on</CODE>, <CODE>warning</CODE>
306
or <CODE>off</CODE> as usual. The checks are switched off in the default
307
mode.<P>
308
There are also equivalent command line options to tchk of the form
309
<CODE>-X:variable=</CODE><CODE>state</CODE>, where <CODE>state</CODE>
310
can be <CODE>check</CODE>, <CODE>warn</CODE> or <CODE>dont</CODE>.<P>
311
The variable analysis is concerned with the evaluation of expressions
312
and the use of local variables, including function arguments. Occasionally
313
it may not be possible to statically perform a full analysis on an
314
expression or variable and in these cases the messages produced indicate
315
that there may be a problem. If a full analysis is possible a definite
316
error or warning is produced. The individual checks are listed in
317
sections 5.6.1 to 5.6.6 and section 5.7 describes the source annotations
318
which can be used to fine-tune the variable analysis.<P>
319
<A NAME=S52>
320
<H3>5.6.1  Order of evaluation</H3>
321
The ISO C standard specifies certain points in the expression syntax
322
at which all prior expressions encountered are guaranteed to have
323
been evaluated. These positions are called sequence points and occur:
324
<P>
325
<UL>
326
<LI>after the arguments and function expression of a function call
327
have been evaluated but before the call itself;<P>
328
<LI>after the first operand of a logical &amp;&amp;, or || operator;
329
<P>
330
<LI>after the first operand of the conditional operator, ?:; <P>
331
<LI>after the first operand of the comma operator; <P>
332
<LI>at the end of any full expression  (a full expression may take
333
one of the following forms: an initialiser; the expression in an expression
334
statement; the controlling expression in an <CODE>if</CODE>, <CODE>while</CODE>,
335
<CODE>do</CODE> or <CODE>switch 
336
</CODE> statement; each of the three optional expressions of a <CODE>for</CODE>
337
statement; or the optional expression of a <CODE>return</CODE> statement).<P>
338
</UL>
339
Between two sequence points however, the order in which the operands
340
of an operator are evaluated, and the order in which side effects
341
take place is unspecified - any order which conforms to the operator
342
precedence rules above is permitted. For example:<P>
343
<PRE>
344
	var = i + arr[ i++ ] ;
345
</PRE>
346
may evaluate to different values on different machines, depending
347
on which argument of the + operator is evaluated first. The checker
348
can detect expressions which depend on the order of evaluation of
349
sub-expressions between sequence points and these are flagged as errors
350
or warnings when the variable analysis is enabled.<P>
351
<A NAME=S53>
352
<H3>5.6.2  Modification between sequence points</H3>
353
The ISO C standard states that if an object is modified more than
354
once, or is modified and accessed other than to determine the new
355
value, between two sequence points, then the behaviour is undefined.
356
Thus the result of:<P>
357
<PRE>
358
	var = arr[i++] + i++ ;
359
</PRE>
360
is undefined, since the value of i is being incremented twice between
361
sequence points. This behaviour is detected by the variable analysis.<P>
362
<A NAME=S54>
363
<H3>5.6.3  Operand of sizeof operator</H3>
364
According to the ISO C standard, section 6.3.3.4, the operand of the
365
sizeof operator is not itself evaluated. If the operand has any side-effects
366
these will not occur. When the variable analysis is enabled, the checker
367
detects the use of expressions with side-effects in the operand of
368
the sizeof operator.<P>
369
<A NAME=S55>
370
<H3>5.6.4  Unused variables</H3>
371
As part of the variable analysis, a simple test applied to each local
372
variable at the end of its scope to determine whether it has been
373
used in that scope. For example, in:<P>
374
<PRE>
375
	int f ( int n )
376
	{
377
		int r;
378
		return ( 0 );
379
	}
380
</PRE>
381
both the function argument n and the local variable r are unused.<P>
382
<A NAME=S56>
383
<H3>5.6.5  Values set and not used</H3>
384
This is a more complex test since it is applied to every instance
385
of setting the variable. For example, in:<P>
386
<PRE>
387
	int f ( int n )
388
	{
389
		int r = 1;
390
		r = 5;
391
		return ( r );
392
	}
393
</PRE>
394
the first value r is set to 1 and is not used before it is overwritten
395
by 5 (this second value is used however). This test requires some
396
flow analysis. For example, if the program is modified to:<P>
397
<PRE>
398
	int f ( int n )
399
	{
400
		int r = 1;
401
		if ( n == 3 ) {
402
			r = 5;
403
		}
404
		return ( r );
405
	}
406
</PRE>
407
the initial value of r is used when n != 3, so no error is detected.
408
However in:<P>
409
<PRE>
410
	int f ( int n )
411
	{
412
		int r = 1;
413
		if ( n == 3 ) {
414
			r = 5;
415
		} else {
416
			r = 6;
417
		}
418
		return ( r );
419
	}
420
</PRE>
421
the initial value of r is overwritten regardless of the result of
422
the conditional, and hence is unused.<P>
423
<A NAME=S57>
424
<H3>5.6.6  Variable which has not been set is used</H3>
425
This test also requires some flow analysis, for example in:<P>
426
<PRE>
427
	int f ( int n )
428
	{
429
		int r;
430
		if ( n == 3 ) {
431
			r = 5;
432
		}
433
		return ( r );
434
	}
435
</PRE>
436
the use of the variable r as a return value is reported because there
437
are paths leading to this statement in which r is not set (i.e. when
438
n != 3). However, in:<P>
439
<PRE>
440
	int f ( int n )
441
	{
442
		int r;
443
		if ( n == 3 ) {
444
			r = 5;
445
		} else {
446
			r = 6;
447
		}
448
		return ( r );
449
	}
450
</PRE>
451
r is always set before it is used, so no error is detected.<P>
452
<A NAME=S58>
453
<HR><H2>5.7  Overriding the variable analysis</H2>
454
Although many of the problems discovered by the variable analysis
455
are genuine mistakes, some may be as the result of deliberate decisions
456
by the program writer. In this case, more information needs to be
457
provided to the checker to convey the programmer's intentions. Four
458
constructs are provided for this purpose: the discard variable, the
459
set variable, the exhaustive switch and the non-returning function.<P>
460
<A NAME=S59>
461
<H3>5.7.1  <A NAME=26>Discarding variables</H3>
462
Actively discarding a variable counts as a use of that variable in
463
the variable analysis, and so can be used to suppress messages concerning
464
unused variables and values assigned to variables. There are two distinct
465
methods to indicate that the variable x is to be discarded. The first
466
uses a pragma:<P>
467
<PRE>
468
	#pragma TenDRA discard x;
469
</PRE>
470
which the checker treats as if it were a C statement, ending in a
471
semicolon. Having a statement which is noticed by one compiler but
472
ignored by another can lead to problems. For example, in:<P>
473
<PRE>
474
	if ( n == 3 )
475
	#pragma TenDRA discard x;
476
		puts ( &quot;n is three&quot; );
477
</PRE>
478
tchk believes that x is discarded if n == 3 and the message is always
479
printed, whereas other compilers will ignore the #pragma statement
480
and think that the message is printed if n == 3. An alternative, in
481
many ways neater, solution is to introduce a new keyword for discarding
482
variables. For example, to introduce the keyword DISCARD for this
483
purpose, the pragma:<P>
484
<PRE>
485
	#pragma TenDRA keyword DISCARD for discard variable
486
</PRE>
487
should be used. The variable x can then be discarded by means of the
488
statement:<P>
489
<PRE>
490
	DISCARD ( x );
491
</PRE>
492
A dummy definition for DISCARD to use with normal compilers needs
493
to be given in order to maintain compilability with those compilers.
494
For example, a complete definition of DISCARD might be:<P>
495
<PRE>
496
	#ifdef __TenDRA__
497
	#pragma TenDRA keyword DISCARD for discard variable
498
	#else
499
	#define DISCARD(x) (( void ) 0 )
500
	#endif
501
</PRE>
502
Discarding a variable changes its assignment state to unset, so that
503
any subsequent uses of the variable, without an intervening assignment
504
to it, lead to a &quot;variable used before being set&quot; error.
505
This feature can be exploited if the same variable is used for distinct
506
purposes in different parts of its scope, by causing the variable
507
analysis to treat the different uses separately. For example, in:<P>
508
<PRE>
509
	void f ( void ) {
510
		int i = 0;
511
		while ( i++ &lt; 10 )
512
			{ puts ( &quot;hello&quot; ); }
513
		while ( i++ &lt; 10 ) 
514
			{ puts ( &quot;goodbye&quot; ); }
515
	}
516
</PRE>
517
which is intended to print both messages ten times, the two uses of
518
i as a loop counter are independent - they could have been implemented
519
with different variables. By discarding i after the first loop, the
520
second loop can be analysed separately. In this way, the error of
521
failing to reset i to 0 can be detected.<P>
522
<A NAME=S60>
523
<H3>5.7.2  <A NAME=29>Setting variables</H3>
524
In addition to discarding variables, it is also possible to set them.
525
In deliberately setting a variable, the programmer is telling the
526
checker to assume that some value will always have been assigned to
527
the variable by that point, so that any &quot;variable used without
528
being set&quot; errors can be suppressed. This construct is particularly
529
useful in programs with complex flow control, to help out the variable
530
analysis. For example, in:<P>
531
<PRE>
532
	void f ( int n )
533
	{
534
		int r;
535
		if ( n != 0 ) r = n;
536
		if ( n &gt; 2 ) {
537
			printf ( &quot;%d\n&quot;, r );
538
		}
539
	}
540
</PRE>
541
r is only used if n &gt; 2, in which case we also have n != 0, so
542
that r has already been initialised. However, in its flow analysis,
543
the TenDRA C checker treats all the conditionals it meets as if they
544
were independent and does not look for any such complex dependencies
545
(indeed it is possible to think of examples where such analysis would
546
be impossible). Instead, it needs the programmer to clarify the flow
547
of the program by asserting that r will be set if the second condition
548
is true.<P>
549
Programmers may assert that the variable, r, is set either by means
550
of a pragma:<P>
551
<PRE>
552
	#pragma TenDRA set r;
553
</PRE>
554
or by using, for example:<P>
555
<PRE>
556
	SET ( r );
557
</PRE>
558
where SET is a keyword which has previously been introduced to stand
559
for the variable setting construct using:<P>
560
<PRE>
561
	#pragma TenDRA keyword SET for set
562
</PRE>
563
(cf. DISCARD above).<P>
564
<P>
565
<A NAME=S61>
566
<H3>5.7.3  <A NAME=32>Exhaustive switch statements 
567
</H3>
568
A special case of a flow control construct which may be used to set
569
the value of a variable is a switch statement. Consider the program:<P>
570
<PRE>
571
	char *f ( int n ){
572
		char *r;
573
		switch ( n ) {
574
			case 1:r=&quot;one&quot;;break;
575
			case 2:r=&quot;two&quot;;break;
576
			case 3:r=&quot;three&quot;;break;
577
		}
578
		return ( r );
579
	}
580
</PRE>
581
This leads to an error indicating that r is used but not set, because
582
it is not set if n lies outside the three cases in the switch statement.
583
However, the programmer might know that f is only ever called with
584
these three values, and hence that r is always set before it is used.
585
This information could be expressed by asserting that r is set at
586
the end of the switch construct (see above), but it would be better
587
to express the cause of this setting rather than just its effect.
588
The reason why r is always set is that <BR>
589
the switch statement is exhaustive - there are case statements for
590
all the possible values of n.<P>
591
Programmers may assert that a switch statement is exhaustive by means
592
of a pragma immediately following it. For example, in the above case
593
it would take the form:<P>
594
<PRE>
595
	....
596
	switch ( n )
597
	#pragma TenDRA exhaustive
598
		{
599
			case 1:r=&quot;one&quot;;break;
600
			....
601
</PRE>
602
Again, there is an option to introduce a keyword, EXHAUSTIVE say,
603
for exhaustive switch statements using:<P>
604
<PRE>
605
	#pragma TenDRA keyword EXHAUSTIVE for exhaustive
606
</PRE>
607
Using this form, the example program becomes:<P>
608
<PRE>
609
	switch ( n ) EXHAUSTIVE {
610
		case 1:r=&quot;one&quot;;break;
611
</PRE>
612
In order to maintain compatibility with existing compilers, a dummy
613
definition for EXHAUSTIVE must be introduced for them to use. For
614
example, a complete definition of EXHAUSTIVE might be:<P>
615
<PRE>
616
	#ifdef __TenDRA__
617
	#pragma TenDRA keyword EXHAUSTIVE for exhaustive
618
	#else
619
	#define EXHAUSTIVE
620
	#endif
621
</PRE>
622
<A NAME=S62>
623
<H3>5.7.4  <A NAME=34>Non-returning functions  
624
</H3>
625
Consider a modified version of the program above, in which calls to
626
f with an argument other than 1, 2 or 3 cause an error message to
627
be printed:<P>
628
<PRE>
629
	extern void error (const char*);
630
	char *f ( int n ) {
631
		char *r;
632
		switch ( n ) {
633
			case 1:r=&quot;one&quot;;break;
634
			case 2:r=&quot;two&quot;;break;
635
			case 3:r=&quot;three&quot;;break;
636
			default:error(&quot;Illegal value&quot;);
637
		}
638
		return ( r );
639
	}
640
</PRE>
641
This causes an error because, in the default case, r is not set before
642
it is used. However, depending on the semantics of the function, error,
643
the return statement may never be reached in this case. This is because
644
the fact that a function returns void can mean one of two distinct
645
things:<P>
646
<OL>
647
<LI>That the function does not return a value. This is the usual meaning
648
of void.<P>
649
<LI>That the function never returns, for example the library function,
650
exit, uses void in this sense.<P>
651
</OL>
652
If error never returns, then the program above is correct; otherwise,
653
an unset value of r may be returned.<P>
654
Therefore, we need to be able to declare the fact that a function
655
never returns. This is done by introducing a new type to stand for
656
the non-returning meaning of void (some compilers use volatile void
657
for this purpose). This is done by means of the pragma:<P>
658
<PRE>
659
	#pragma TenDRA type VOID for bottom
660
</PRE>
661
to introduce a type VOID (although any identifier may be used) with
662
this meaning. The declaration of error can then be expressed as:<P>
663
<PRE>
664
	extern VOID error (const char *);
665
</PRE>
666
In order to maintain compatibility with existing compilers a definition
667
of VOID needs to be supplied. For example:<P>
668
<PRE>
669
	#ifdef __TenDRA__
670
	#pragma TenDRA type VOID for bottom
671
	#else
672
	typedef void VOID;
673
	#endif
674
</PRE>
675
The largest class of non-returning functions occurs in the various
676
standard APIs - for example, exit and abort. The TenDRA descriptions
677
of these APIs contain this information. The information that a function
678
does not return is taken into account in all flow analysis contexts.
679
For example, in:<P>
680
<PRE>
681
	#include &lt;stdlib.h&gt;
682
 
683
	int f ( int n )
684
	{
685
		exit ( EXIT_FAILURE );
686
		return ( n );
687
	}
688
</PRE>
689
n is unused because the return statement is not reached (a fact that
690
can also be determined by the unreachable code analysis in section
691
5.2).<P>
692
<A NAME=S63>
693
<HR><H2>5.8  <A NAME=36>Discard Analysis</H2>
694
A couple of examples of what might be termed &quot;discard analysis&quot;
695
have already been described - discarded (unused) local variables and
696
discarded (unused) assignments to local variables (see section 5.6.4
697
and 5.6.5). The checker can perform three more types of discard analysis:
698
discarded function returns, discarded computations and unused static
699
variables and procedures. These three tests may be controlled as a
700
group using:<P>
701
<PRE>
702
	#pragma TenDRA discard analysis <EM>status</EM>
703
</PRE>
704
where <EM>status</EM> is <CODE>on</CODE>, <CODE>warning</CODE> or
705
<CODE>off</CODE>.<P>
706
In addition, each of the component tests may be switched on and off
707
independently using pragmas of the form:<P>
708
<PRE>
709
	#pragma TenDRA discard analysis (function return) <EM>status</EM>
710
	#pragma TenDRA discard analysis (value) <EM>status</EM>
711
	#pragma TenDRA discard analysis (static) <EM>status</EM>
712
</PRE>
713
There are also equivalent command line options to tchk of the form
714
<CODE>-X:</CODE><CODE>test</CODE><CODE>=</CODE><CODE>state</CODE>,
715
where <CODE>test</CODE> can be <CODE>discard_all</CODE>, <CODE>discard_func_ret
716
</CODE>, <CODE>discard_value</CODE> or <CODE>unused_static</CODE>,
717
and <CODE>state</CODE> can be <CODE>check</CODE>, <CODE>warn</CODE>
718
or <CODE>dont</CODE>. These checks are all switched off in the default
719
mode. <P>
720
Detailed descriptions of the individual checks follow in sections
721
5.8.1 - 5.8.3. Section 5.9 describes the facilities for fine-tuning
722
the discard analysis.<P>
723
<A NAME=S64>
724
<H3>5.8.1  <A NAME=38>Discarded function returns</H3>
725
Functions which return a value which is not used form the commonest
726
instances of discarded values. For example, in:<P>
727
<PRE>
728
	#include &lt;stdio.h&gt;
729
	int main ()
730
	{
731
		puts ( &quot;hello&quot; );
732
		return ( 0 );
733
	}
734
</PRE>
735
the function, puts, returns an int value, indicating whether an error
736
has occurred, which is ignored.<P>
737
<A NAME=S65>
738
<H3>5.8.2  <A NAME=40>Discarded computed values</H3>
739
A rarer instance of a discarded object, and one which is almost always
740
an error, is where a value is computed but not used. For example,
741
in:<P>
742
<PRE>
743
	int f ( int n ) {
744
		int r = 4 
745
		if ( n == 3 ) {
746
			r == 5;
747
		}
748
		return ( r );
749
	}
750
</PRE>
751
the value r == 5 is computed but not used. This is actually because
752
it is a misprint for r = 5.<P>
753
<A NAME=S66>
754
<H3>5.8.3  <A NAME=42>Unused static variables and procedures</H3>
755
The final example of discarded values, which perhaps more properly
756
belongs with the variable analysis tests mentioned above, is for static
757
objects which are unused in the source module in which they are defined.
758
Of course this means that they are unused in the entire program. Such
759
objects can usually be removed.<P>
760
<A NAME=S67>
761
<HR><H2>5.9  Overriding the discard analysis</H2>
762
As with the variable analysis, certain constructs may be used to provide
763
the checker with extra information about a program, to convey the
764
programmer's intentions more clearly.<P>
765
<A NAME=S68>
766
<H3>5.9.1  <A NAME=44>Discarding function returns and computed values</H3>
767
Unwanted function returns and, more rarely, discarded computed values,
768
may be actively ignored to indicate to the discard analysis that the
769
value is being discarded deliberately. This can be done using the
770
traditional method of casting the value to void:<P>
771
<PRE>
772
	( void ) puts ( &quot;hello&quot; );
773
</PRE>
774
or by introducing a keyword, IGNORE say, for discarding a value. This
775
is done using a pragma of the form:<P>
776
<PRE>
777
	#pragma TenDRA keyword IGNORE for discard value
778
</PRE>
779
The example discarded value then becomes:<P>
780
<PRE>
781
	IGNORE puts ( &quot;hello&quot; );
782
</PRE>
783
Of course it is necessary to introduce a definition of IGNORE for
784
conventional compilers in order to maintain compilability. A suitable
785
definition might be:<P>
786
<PRE>
787
	#ifdef __TenDRA__
788
	#pragma TenDRA keyword IGNORE for discard value
789
	#else
790
	#define IGNORE ( void )
791
	#endif
792
</PRE>
793
<A NAME=S69>
794
<H3>5.9.2  <A NAME=46>Preserving unused statics</H3>
795
Occasionally unused static values are introduced deliberately into
796
programs. The fact that the static variables or procedures x, y and
797
z are deliberately unused may be indicated by introducing the pragma:<P>
798
<PRE>
799
	#pragma TenDRA suspend static x y z
800
</PRE>
801
at the outer level after the definition of all three objects.<P>
802
<P>
803
<!-- FM pgf ignored -->
804
<HR>
805
<P><I>Part of the <A HREF="../index.html">TenDRA Web</A>.<BR>Crown
806
Copyright &copy; 1998.</I></P>
807
</BODY>
808
</HTML>