Subversion Repositories tendra.SVN

Rev

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: Type Checking</TITLE>
5
</HEAD>
6
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#400080" ALINK="#FF0000">
7
<A NAME=S15>
8
<H1>C Checker Reference Manual</H1>
9
<H3>January 1998</H3>
10
<A HREF="tdfc7.html"><IMG SRC="../images/next.gif" ALT="next section"></A>
11
<A HREF="tdfc5.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="#S16"><B>3.1 </B> - Introduction</A><DD>
19
<DT><A HREF="#S17"><B>3.2 </B> - Type conversions</A><DD>
20
<DL>
21
<DT><A HREF="#S18"><B>3.2.1 </B> - Integer to integer conversions
22
</A><DD>
23
<DT><A HREF="#S19"><B>3.2.2 </B> - Pointer to integer and integer
24
to pointer conversions</A><DD>
25
<DT><A HREF="#S20"><B>3.2.3 </B> - Pointer to pointer conversions
26
</A><DD>
27
<DT><A HREF="#S21"><B>3.2.4 </B> - Example: 64-bit portability issues</A><DD>
28
</DL>
29
<DT><A HREF="#S22"><B>3.3 </B> - Function type checking</A><DD>
30
<DL>
31
<DT><A HREF="#S23"><B>3.3.1 </B> - Type checking non-prototyped functions</A>
32
<DD>
33
<DT><A HREF="#S24"><B>3.3.2 </B> - Checking printf strings</A><DD>
34
<DT><A HREF="#S25"><B>3.3.3 </B> - Function return checking</A><DD>
35
</DL>
36
<DT><A HREF="#S26"><B>3.4 </B> - Overriding type checking</A><DD>
37
<DL>
38
<DT><A HREF="#S27"><B>3.4.1 </B> - Implicit Function Declarations</A><DD>
39
<DT><A HREF="#S28"><B>3.4.2 </B> - Function Parameters</A><DD>
40
<DT><A HREF="#S29"><B>3.4.3 </B> - Incompatible promoted function
41
arguments</A><DD>
42
<DT><A HREF="#S30"><B>3.4.4 </B> - Incompatible type qualifiers</A><DD>
43
</DL>
44
</DL>
45
 
46
<HR>
47
<H1>3  Type Checking</H1>
48
<A NAME=S16>
49
<HR><H2>3.1  Introduction</H2>
50
Type checking is relevant to two main areas of C. It ensures that
51
all declarations referring to the same object are consistent (clearly
52
a pre-requisite for a well-defined program). It is also the key to
53
determining when an undefined or unexpected value has been produced
54
due to the type conversions which arise from certain operations in
55
C. Conversions may be explicit (conversion is specified by a cast)
56
or implicit. Generally explicit conversions may be regarded more leniently
57
since the programmer was obviously aware of the conversion, whereas
58
the implications of an implicit conversion may not have been considered.<P>
59
<A NAME=S17>
60
<HR><H2>3.2  <A NAME=2>Type conversions</H2>
61
The only types which may be interconverted legally are integral types,
62
floating point types and pointer types. Even if these rules are observed,
63
the results of some conversions can be surprising and may vary on
64
different machines. The checker can detect three categories of conversion:
65
integer to integer conversions, pointer to integer and integer to
66
pointer conversions, and pointer to pointer conversions.<P>
67
In the default mode, the checker allows all integer to integer conversions,
68
explicit integer to pointer and pointer to integer conversions and
69
the explicit pointer to pointer conversions defined by the ISO C standard
70
(all conversions between pointers to function types and other pointers
71
are undefined according to the ISO C standard).<P>
72
Checks to detect these conversions are controlled by the pragma:<P>
73
<PRE>
74
	#pragma TenDRA conversion analysis <EM>status</EM>
75
</PRE>
76
Unless explicitly stated to the contrary, throughout the rest of the
77
document where <EM>status</EM> appears in a pragma statement it represents
78
one of <CODE>on</CODE> (enable the check and produce errors), 
79
<CODE>warning</CODE> (enable the check but produce only warnings),
80
or <CODE>off</CODE> (disable the check). Here <EM>status</EM> may
81
be <CODE>on</CODE> to give an error if a conversion is detected, <CODE>warning
82
</CODE> to produce a warning if a conversion is detected, or <CODE>off</CODE>
83
to switch the checks off. The checks may also be controlled using
84
the command line option<CODE>
85
-X:</CODE><EM>test</EM><CODE>=</CODE><EM>state</EM><CODE> </CODE>where
86
<EM>test</EM> is one of <CODE>convert_all</CODE>, <CODE>convert_int</CODE>,
87
<CODE>convert_int_explicit</CODE>, <CODE>convert_int_implicit</CODE>,
88
<CODE>convert_int_ptr</CODE> and <CODE>convert_ptr</CODE> and <EM>state</EM>
89
is <CODE>check</CODE>,<CODE>warn</CODE> or <CODE>dont</CODE>.<P>
90
Due to the serious nature of implicit pointer to integer, implicit
91
pointer to pointer conversions and undefined explicit pointer to pointer
92
conversions, such conversions are flagged as errors by default. These
93
conversion checks are not controlled by the global conversion analysis
94
pragma above, but must be controlled by the relevant individual pragmas
95
given in sections <A HREF="#8">3.2.2</A> and <A HREF="#11">3.2.3</A>.<P>
96
<A NAME=S18>
97
<H3>3.2.1  <A NAME=5>Integer to integer conversions</H3>
98
All integer to integer conversions are allowed in C, however some
99
can result in a loss of accuracy and so may be usefully detected.
100
For example, conversions from int to long never result in a loss of
101
accuracy, but conversions from long to int may. The detection of these
102
shortening conversions is controlled by:<P>
103
<PRE>
104
	#pragma TenDRA conversion analysis ( int-int ) <EM>status</EM>
105
</PRE>
106
Checks on explicit conversions and implicit conversions may be controlled
107
independently using:<P>
108
<PRE>
109
	#pragma TenDRA conversion analysis ( int-int explicit ) <EM>status</EM>
110
</PRE>
111
and<P>
112
<PRE>
113
	#pragma TenDRA conversion analysis ( int-int implicit ) <EM>status</EM>
114
</PRE>
115
Objects of enumerated type are specified by the ISO C standard to
116
be compatible with an implementation-defined integer type. However
117
assigning a value of a different integral type other then an appropriate
118
enumeration constant to an object of enumeration type is not really
119
in keeping with the spirit of enumerations. The check to detect the
120
implicit integer to enum type conversions which arise from such assignments
121
is controlled using:<P>
122
<PRE>
123
	#pragma TenDRA conversion analysis ( int-enum implicit ) <EM>status</EM> 
124
</PRE>
125
Note that only implicit conversions are flagged; if the conversion
126
is made explicit, by using a cast, no errors are raised. <P>
127
As usual <EM>status</EM> must be replaced by <CODE>on</CODE>, <CODE>warning
128
</CODE> or <CODE>off</CODE> in all the pragmas listed above.<P>
129
The interaction of the integer conversion checks with the integer
130
promotion and arithmetic rules is an extremely complex issue which
131
is further discussed in Chapter 4.<P>
132
<A NAME=S19>
133
<H3>3.2.2  <A NAME=8>Pointer to integer and integer to pointer conversions</H3>
134
Integer to pointer and pointer to integer conversions are generally
135
unportable and should always be specified by means of an explicit
136
cast. The exception is that the integer zero and null pointers are
137
deemed to be inter-convertible. As in the integer to integer conversion
138
case, explicit and implicit pointer to integer and integer to pointer
139
conversions may be controlled separately using:<P>
140
<PRE>
141
	#pragma TenDRA conversion analysis ( int-pointer explicit ) <EM>status</EM>
142
</PRE>
143
and<P>
144
<PRE>
145
	#pragma TenDRA conversion analysis ( int-pointer implicit ) <EM>status</EM>
146
</PRE>
147
or both checks may be controlled together by:<P>
148
<PRE>
149
	#pragma TenDRA conversion analysis ( int-pointer ) <EM>status</EM>
150
</PRE>
151
where <EM>status</EM> may be <CODE>on</CODE>, <CODE>warning</CODE>
152
or <CODE>off</CODE> as before and <CODE>pointer-int</CODE> may be
153
substituted for <CODE>int-pointer</CODE>.<P>
154
<P>
155
<A NAME=S20>
156
<H3>3.2.3  <A NAME=11>Pointer to pointer conversions. 
157
</H3>
158
According to the ISO C standard, section 6.3.4, the only legal pointer
159
to pointer conversions are explicit conversions between:<P>
160
<OL>
161
<LI>a pointer to an object or incomplete type and a pointer to a different
162
object or incomplete type. The resulting pointer may not be valid
163
if it is improperly aligned for the type pointed to;<P>
164
<LI>a pointer to a function of one type and a pointer to a function
165
of another type. If a converted pointer, used to call a function,
166
has a type that is incompatible with the type of the called function,
167
the behaviour is undefined.<P>
168
</OL>
169
Except for conversions to and from the generic pointer which are discussed
170
below, all other conversions, including implicit pointer to pointer
171
conversions, are extremely unportable. <P>
172
All pointer to pointer conversion may be flagged as errors using:<P>
173
<PRE>
174
	#pragma TenDRA conversion analysis ( pointer-pointer ) <EM>status</EM>
175
</PRE>
176
Explicit and implicit pointer to pointer conversions may be controlled
177
separately using:<P>
178
<PRE>
179
	#pragma TenDRA conversion analysis ( pointer-pointer explicit ) <EM>status</EM>
180
</PRE>
181
and<P>
182
<PRE>
183
	#pragma TenDRA conversion analysis ( pointer-pointer implicit ) <EM>status</EM>
184
</PRE>
185
where, as before, <CODE>status</CODE> may be <CODE>on</CODE>, <CODE>warning
186
</CODE> or <CODE>off</CODE>.<P>
187
Conversion between a pointer to a function type and a pointer to a
188
non-function type is undefined by the ISO C standard and should generally
189
be avoided. The checker can however be configured to treat function
190
pointers as object pointers for conversion using:<P>
191
<PRE>
192
	#pragma TenDRA function pointer as pointer <EM>permit</EM>
193
</PRE>
194
Unless explicitly stated to the contrary, throughout the rest of the
195
document where <EM>permit</EM> appears in a pragma statement it represents
196
one of <CODE>allow</CODE> (allow the construct and do not produce
197
errors), <CODE>warning</CODE> (allow the construct but produce warnings
198
when it is detected), or <CODE>disallow</CODE> (produce errors if
199
the construct is detected) Here there are three options for <EM>permit</EM>:
200
<CODE>allow 
201
</CODE> (do not produce errors or warnings for function pointer &lt;-&gt;
202
pointer conversions); <CODE>warning</CODE> (produce a warning when
203
function pointer &lt;-&gt; pointer conversions are detected); or <CODE>disallow
204
</CODE> (produce an error for function pointer &lt;-&gt; pointer conversions).
205
<P>
206
The generic pointer, void *, is a special case. All conversions of
207
pointers to object or incomplete types to or from a generic pointer
208
are allowed. Some older dialects of C used char * as a generic pointer.
209
This dialect feature may be allowed, allowed with a warning, or disallowed
210
using the pragma:<P>
211
<PRE>
212
	#pragma TenDRA compatible type : char * == void * <EM>permit</EM>
213
</PRE>
214
where <EM>permit </EM>is <CODE>allow</CODE>, <CODE>warning</CODE>
215
or <CODE>disallow</CODE> as before.<P>
216
<A NAME=S21>
217
<H3>3.2.4  <A NAME=15>Example: 64-bit portability issues</H3>
218
64-bit machines form the &quot;next frontier&quot; of program portability.
219
Most of the problems involved in 64-bit portability are type conversion
220
problems. The assumptions that were safe on a 32-bit machine are not
221
necessarily true on a 64-bit machine - int may not be the same size
222
as long, pointers may not be the same size as int, and so on. This
223
example illustrates the way in which the checker's conversion analysis
224
tests can detect potential 64-bit portability problems.<P>
225
Consider the following code:<P>
226
<PRE>
227
	#include &lt;stdio.h&gt;
228
	void print ( string, offset, scale )
229
	char *string;
230
	unsigned int offset;
231
	int scale;
232
	{
233
		string += ( scale * offset );
234
		( void ) puts ( string );
235
		return;
236
	}
237
 
238
	int main ()
239
	{
240
		char *s = &quot;hello there&quot;;
241
		print ( s + 4, 2U, -2 );
242
		return ( 0 );
243
	}
244
</PRE>
245
This appears to be fairly simple - the offset of 2U scaled by -2 cancels
246
out the offset in s + 4, so the program just prints &quot;hello there&quot;.
247
Indeed, this is what happens on most machines. When ported to a particular
248
64-bit machine, however, it core dumps. The fairly subtle reason is
249
that the composite offset, scale * offset, is actually calculated
250
as an unsigned int by the ISO C arithmetic conversion rules. So the
251
answer is not -4. Strictly speaking it is undefined, but on virtually
252
all machines it will be UINT_MAX - 3. The fact that adding this offset
253
to string is equivalent to adding -4 is only true on machines on which
254
pointers have the same size as unsigned int. If a pointer contains
255
64 bits and an unsigned int contains 32 bits, the result is 232 bytes
256
out.<P>
257
So the error occurs because of the failure to spot that the offset
258
being added to string is unsigned. All mixed integer type arithmetic
259
involves some argument conversion. In the case above, scale is converted
260
to an unsigned int and that is multiplied by offset to give an unsigned
261
int result. If the implicit int-&gt;int conversion checks (<A HREF="#5">3.2.1
262
</A>) are enabled, this conversion is detected and the problem may
263
be avoided.<P>
264
<A NAME=S22>
265
<HR><H2>3.3  <A NAME=17>Function type checking</H2>
266
The importance of function type checking in C lies in the conversions
267
which can result from type mismatches between the arguments in a function
268
call and the parameter types assumed by its definition or between
269
the specified type of the function return and the values returned
270
within the function definition. Until the introduction of function
271
prototypes into ISO standard C, there was little scope for detecting
272
the correct typing of functions. Traditional C allows for absolutely
273
no type checking of function arguments, so that totally bizarre functions,
274
such as:<P>
275
<PRE>
276
	int f ( n ) int n ; {
277
		return ( f ( &quot;hello&quot;, &quot;there&quot; ) ) ;
278
	}
279
</PRE>
280
are allowed, although their effect is undefined. However, the move
281
to fully prototyped programs has been relatively slow. This is partially
282
due to an understandable reluctance to change existing, working programs,
283
but the desire to maintain compatibility with existing C compilers,
284
some of which still do not support prototypes, is also a powerful
285
factor. Prototypes are allowed in the checker's default mode but tchk
286
can be configured to allow, allow with a warning or disallow prototypes,
287
using:<P>
288
<PRE>
289
	#pragma TenDRA prototype <EM>permit</EM>
290
</PRE>
291
where <EM>permit </EM>is <CODE>allow</CODE>, <CODE>disallow</CODE>
292
or <CODE>warning</CODE>. <P>
293
Even if prototypes are not supported the checker has a facility, described
294
below, for detecting incorrectly typed functions.<P>
295
<A NAME=S23>
296
<H3>3.3.1  <A NAME=20>Type checking non-prototyped functions</H3>
297
The checker offers a method for applying prototype-like checks to
298
traditionally defined functions, by introducing the concept of &quot;
299
weak&quot; prototypes. A weak prototype contains function parameter
300
type information, but has none of the automatic argument conversions
301
associated with a normal prototype. Instead weak prototypes imply
302
the usual argument promotion passing rules for non-prototyped functions.
303
The type information required for a weak prototype can be obtained
304
in three ways:<P>
305
<OL>
306
<LI>A weak prototype may be declared using the syntax:<P>
307
<PRE>
308
	int f <EM>WEAK</EM> ( char, char * ) ;
309
</PRE>
310
where<EM> WEAK</EM> represents any keyword which has been introduced
311
using:<P>
312
<PRE>
313
	#pragma TenDRA keyword <EM>WEAK</EM> for weak
314
</PRE>
315
An alternative definition of the keyword must be provided for other
316
compilers. For example, the following definition would make system
317
compilers interpret weak prototypes as normal (strong) prototypes:<P>
318
<PRE>
319
	#ifdef __TenDRA__
320
	#pragma TenDRA keyword WEAK for weak
321
	#else
322
	#define WEAK
323
	#endif
324
</PRE>
325
The difference between conventional prototypes and weak prototypes
326
can be illustrated by considering the normal prototype for f: 
327
<PRE>
328
	int f (char,char *);
329
</PRE>
330
When the prototype is present, the first argument to f would be passed
331
as a char. Using the weak prototype, however, results in the first
332
argument being passed as the integral promotion of char, that is to
333
say, as an int.<P>
334
There is one limitation on the declaration of weak prototypes - declarations
335
of the form: 
336
<PRE>
337
	int f <EM>WEAK</EM>() ;
338
</PRE>
339
are not allowed. If a function has no arguments, this should be stated
340
explicitly as:<P>
341
<PRE>
342
	int f <EM>WEAK</EM>( void ) ;
343
</PRE>
344
whereas if the argument list is not specified, weak prototypes should
345
be avoided and a traditional declaration used instead:<P>
346
<PRE>
347
	extern int f ();
348
</PRE>
349
The checker may be configured to allow, allow with a warning or disallow
350
weak prototype declarations using: 
351
<PRE>
352
	#pragma TenDRA prototype ( weak ) <EM>permit</EM>
353
</PRE>
354
where <CODE>permit</CODE> is replaced by <CODE>allow</CODE>, <CODE>warning
355
</CODE> or <CODE>disallow</CODE> as appropriate. Weak prototypes are
356
not permitted in the default mode.<P>
357
<LI>Information can be deduced from a function definition. For example,
358
the function definition:<P>
359
<PRE>
360
	int f(c,s) char c; char *s;{...}
361
</PRE>
362
is said to have weak prototype:<P>
363
<PRE>
364
	int f <EM>WEAK</EM> (char,char *);
365
</PRE>
366
The checker automatically constructs a weak prototype for each traditional
367
function definition it encounters and if the weak prototype analysis
368
mode is enabled (see below) all subsequent calls of the function are
369
checked against this weak prototype. <P>
370
For example, in the bizarre function in <A HREF="#17">3.3</A>, the
371
weak prototype:<P>
372
<PRE>
373
	int f <EM>WEAK</EM> ( int );
374
</PRE>
375
is constructed for f. The subsequent call to f:<P>
376
<PRE>
377
	f ( &quot;hello&quot;, &quot;there&quot; );
378
</PRE>
379
is then rejected by comparison with this weak prototype - not only
380
is f called with the wrong number of arguments, but the first argument
381
has a type incompatible with (the integral promotion of) int.<P>
382
<LI>Information may be deduced from the calls of a function. For example,
383
in:<P>
384
<PRE>
385
	extern void f ();
386
	void g ()
387
	{
388
		f ( 3 );
389
		f ( &quot;hello&quot; );
390
	}
391
</PRE>
392
we can infer from the first call of f that f takes one integral argument.
393
We cannot deduce the type of this argument, only that it is an integral
394
type whose promotion is int (since this is how the argument is passed).
395
We can therefore infer a partial weak prototype for f:<P>
396
<PRE>
397
	void f <EM>WEAK</EM> ( t );
398
</PRE>
399
for some integral type t which promotes to int. Similarly, from the
400
second call of f we can infer the weak prototype:<P>
401
<PRE>
402
	void f <EM>WEAK</EM> ( char * );
403
</PRE>
404
(the argument passing rules are much simpler in this case). Clearly
405
the two inferred prototypes are incompatible, so an error is raised.<P>
406
Note that prototype inferred from function calls alone cannot ensure
407
that the uses of the function within a source file are correct, merely
408
that they are consistent. The presence of an explicit function declaration
409
or definition is required for a definitive &quot;right&quot; prototype.<P>
410
Null pointers cause particular problems with weak prototypes inferred
411
from function calls. For example, in:<P>
412
<PRE>
413
	#include &lt;stdio.h&gt;
414
	extern void f ();
415
	void g () {
416
		f ( &quot;hello&quot; );
417
		f( NULL );
418
	}<P>
419
</PRE>
420
the argument in the first call of f is char* whereas in the second
421
it is int (because NULL is defined to be 0). Whereas NULL can be converted
422
to char*, it is not necessarily passed to procedures in the same way
423
(for example, it may be that pointers have 64 bits and ints have 32
424
bits). It is almost always necessary to cast NULL to the appropriate
425
pointer type in weak procedure calls.<P>
426
</OL>
427
Functions for which explicitly declared weak prototypes are provided
428
are always type-checked by the checker. Weak prototypes deduced from
429
function declarations or calls are used for type checking if the weak
430
prototype analysis mode is enabled using:<P>
431
<PRE>
432
	#pragma TenDRA weak prototype analysis <EM>status</EM>
433
</PRE>
434
where <CODE>status</CODE> is one of <CODE>on</CODE>, <CODE>warning</CODE>
435
and <CODE>off</CODE> as usual. Weak prototype analysis is not performed
436
in the default mode.<P>
437
There is also an equivalent command line option of the form <CODE>-X:weak_proto=
438
</CODE><CODE>state</CODE>, where <CODE>state</CODE> can be <CODE>check</CODE>,
439
<CODE>warn</CODE> or <CODE>dont</CODE>. <P>
440
This section ends with two examples which demonstrate some of the
441
less obvious consequences of weak prototype analysis.<P>
442
<P>
443
<B>Example 1: An obscure type mismatch</B><P>
444
As stated above, the promotion and conversion rules for weak prototypes
445
are precisely those for traditionally declared and defined functions.
446
Consider the program:<P>
447
<PRE>
448
	void f ( n )long n;{
449
		printf ( &quot;%ld\n&quot;, n );
450
	}
451
	void g (){
452
		f ( 3 );
453
	}
454
</PRE>
455
The literal constant 3 is an int and hence is passed as such to f.
456
f is however expecting a long, which can lead to problems on some
457
machines. Introducing a strong prototype declaration of f for those
458
compilers which understand them:<P>
459
<PRE>
460
	#ifdef __STDC__ 
461
		void f ( long );
462
	#endif
463
</PRE>
464
will produce correct code - the arguments to a function declared with
465
a prototype are converted to the appropriate types, so that the literal
466
is actually passed as 3L. This solves the problem for compilers which
467
understand prototypes, but does not actually detect the underlying
468
error. Weak prototypes, because they use the traditional argument
469
passing rules, do detect the error. The constructed weak prototype:<P>
470
<PRE>
471
	void f <EM>WEAK</EM> ( long );
472
</PRE>
473
conveys the type information that f is expecting a long, but accepts
474
the function arguments as passed rather than converting them. Hence,
475
the error of passing an int argument to a function expecting a long
476
is detected.<P>
477
Many programs, seeking to have prototype checks while preserving compilability
478
with non-prototype compilers, adopt a compromise approach of traditional
479
definitions plus prototype declarations for those compilers which
480
understand them, as in the example above. While this ensures correct
481
argument passing in the prototype case, as the example shows it may
482
obscure errors in the non-prototype case.<P>
483
<P>
484
<B>Example 2: Weak prototype checks in defined programs</B><P>
485
In most cases a program which fails to compile with the weak prototype
486
analysis enabled is undefined. ISO standard C does however contain
487
an anomalous rule on equivalence of representation. For example, in:<P>
488
<PRE>
489
	extern void f ();
490
	void g () {
491
		f ( 3 );
492
		f ( 4U );
493
	}
494
</PRE>
495
the TenDRA checker detects an error - in one instance f is being passed
496
an int, whereas in the other it is being passed an unsigned int. However,
497
the ISO C standard states that, for values which fit into both types,
498
the representation of a number as an int is equal to that as an unsigned
499
int, and that values with the same representation are interchangeable
500
in procedure arguments. Thus the program is defined. The justification
501
for raising an error or warning for this program is that the prototype
502
analysis is based on types, not some weaker notion of &quot;equivalence
503
of representation&quot;. The program may be defined, but it is not
504
type correct.<P>
505
Another case in which a program is defined, but not correct, is where
506
an unnecessary extra argument is passed to a function. For example,
507
in:<P>
508
<PRE>
509
	void f ( a ) int a; {
510
		printf ( &quot;%d\n&quot;, a );
511
	}
512
	void g () {
513
		f ( 3, 4 );
514
	}
515
</PRE>
516
the call of f is defined, but is almost certainly a mistake.<P>
517
<A NAME=S24>
518
<H3>3.3.2  <A NAME=23>Checking printf strings  
519
</H3>
520
Normally functions which take a variable number of arguments offer
521
only limited scope for type checking. For example, given the prototype:<P>
522
<PRE>
523
	int execl ( const char *, const char *, ... );
524
</PRE>
525
the first two arguments may be checked, but we have no hold on any
526
subsequent arguments (in fact in this example they should all be const
527
char *, but C does not allow this information to be expressed). Two
528
classes of functions of this form, namely the printf and scanf families,
529
are so common that they warrant special treatment. If one of these
530
functions is called with a constant format string, then it is possible
531
to use this string to deduce the types of the extra arguments that
532
it is expect ing. For example, in:<P>
533
<PRE>
534
	printf ( &quot;%ld&quot;, 4 );
535
</PRE>
536
the format string indicates that printf is expecting a single additional
537
argument of type long. We can therefore deduce a <EM>quasi-prototype</EM>
538
which this particular call to printf should conform to, namely:<P>
539
<PRE>
540
	int printf ( const char *,long );
541
</PRE>
542
In fact this is a mixture of a strong prototype and a weak prototype.
543
The first argument comes from the actual prototype of printf, and
544
hence is strong. All subsequent arguments correspond to the ellipsis
545
part of the printf prototype, and are passed by the normal promotion
546
rules. Hence the long component of the inferred prototype is weak
547
(see 3.3.1). This means that the error in the call to printf - the
548
integer literal is passed as an int when a long is expected - is detected.<P>
549
In order for this check to take place, the function declaration needs
550
to tell the checker that the function is like printf. This is done
551
by introducing a special type, <EM>PSTRING</EM> say, to stand for
552
a printf string, using:<P>
553
<PRE>
554
	#pragma TenDRA type <EM>PSTRING</EM> for ... printf
555
</PRE>
556
For most purposes this is equivalent to:<P>
557
<PRE>
558
	typedef const char *<EM>PSTRING</EM>;
559
</PRE>
560
except that when a function declaration:<P>
561
<PRE>
562
	int f ( <EM>PSTRING</EM>, ... );
563
</PRE>
564
is encountered the checker knows to deduce the types of the arguments
565
corresponding to the ... from the PSTRING argument (the precise rules
566
it applies are those set out in the XPG4 definition of fprintf). If
567
this mechanism is used to apply printf style checks to user defined
568
functions, an alternative definition of PSTRING for conventional compilers
569
must be provided. For example:<P>
570
<PRE>
571
	#ifdef __TenDRA__
572
	#pragma TenDRA type PSTRING for ... printf
573
	#else
574
	typedef const char *PSTRING;
575
	#endif
576
</PRE>
577
There are similar rules with scanf in place of printf.<P>
578
The TenDRA descriptions of the standard APIs use this mechanism to
579
describe those functions, namely printf, fprintf and sprintf, and
580
scanf, fscanf and sscanf which are of these forms. This means that
581
the checks are switched on for these functions by default. However,
582
these descriptions are under the control of a macro, __NO_PRINTF_CHECKS,
583
which, if defined before stdio.h is included, effectively switches
584
the checks off. This macro is defined in the start-up files for certain
585
checking modes, so that the checks are disabled in these modes (see
586
chapter 2). The checks can be enabled in these cases by #undef'ing
587
the macro before including stdio.h. There are equivalent command-line
588
options to tchk of the form <CODE>-X:printf=</CODE><CODE>state</CODE>,
589
where <CODE>state</CODE> can be <CODE>check</CODE> or <CODE>dont</CODE>,
590
which respectively undefine and define this macro.<P>
591
<A NAME=S25>
592
<H3>3.3.3  <A NAME=25>Function return checking 
593
</H3>
594
Function returns normally present no difficulties. The return value
595
is converted, as if by assignment, to the function return type, so
596
that the problem is essentially one of type conversion (see 3.2).
597
There is however one anomalous case. A plain return statement, without
598
a return value, is allowed in functions returning a non-void type,
599
the value returned being undefined. For example, in:<P>
600
<PRE>
601
	int f ( int c )
602
	{
603
		if ( c ) return ( 1 );
604
		return;
605
	}
606
</PRE>
607
the value returned when c is zero is undefined. The test for detecting
608
such void returns is controlled by:<P>
609
<PRE>
610
	#pragma TenDRA incompatible void return <EM>permit</EM>
611
</PRE>
612
where <EM>permit</EM> may be <CODE>allow</CODE>, <CODE>warning</CODE>
613
or <CODE>disallow</CODE> as usual. <P>
614
There are also equivalent command line options to tchk of the form
615
<CODE>-X:void_ret=</CODE><CODE>state</CODE>, where <CODE>state</CODE>
616
can be <CODE>check</CODE>, <CODE>warn</CODE> or <CODE>dont</CODE>.
617
Incompatible void returns are allowed in the default mode and of course,
618
plain return statements in functions returning void are always legal.<P>
619
This check also detects functions which do not contain a return statement,
620
but fall out of the bottom of the function as in:<P>
621
<PRE>
622
	int f ( int c )
623
	{
624
		if ( c ) return ( 1 );
625
	}
626
</PRE>
627
Occasionally it may be the case that such a function is legal, because
628
the end of the function is not reached. Unreachable code is discussed
629
in section <A HREF="tdfc8.html#2">5.2</A>.<P>
630
<A NAME=S26>
631
<HR><H2>3.4  Overriding type checking</H2>
632
There are several commonly used features of C, some of which are even
633
allowed by the ISO C standard, which can circumvent or hinder the
634
type-checking of a program. The checker may be configured either to
635
enforce the absence of these features or to support them with or without
636
a warning, as described below.<P>
637
<A NAME=S27>
638
<H3>3.4.1  <A NAME=30>Implicit Function Declarations 
639
</H3>
640
The ISO C standard states that any undeclared function is implicitly
641
assumed to return int. For example, in ISO C:<P>
642
<PRE>
643
	int f ( int c ) {
644
		return ( g( c )+1 );
645
	}
646
</PRE>
647
the undeclared function g is inferred to have a declaration:<P>
648
<PRE>
649
	extern int g ();
650
</PRE>
651
This can potentially lead to program errors. The definition of f would
652
be valid if g actually returned double, but incorrect code would be
653
produced. Again, an explicit declaration might give us more information
654
about the function argument types, allowing more checks to be applied.<P>
655
Therefore the best chance of detecting bugs in a program and ensuring
656
its portability comes from having each function declared before it
657
is used. This means detecting implicit declarations and replacing
658
them by explicit declarations. By default implicit function declarations
659
are allowed, however the pragma:<P>
660
<PRE>
661
	#pragma TenDRA implicit function declaration <EM>status</EM>
662
</PRE>
663
may be used to determine how tchk handles implicit function declarations.
664
<CODE>Status</CODE> is replaced by <CODE>on</CODE> to allow implicit
665
declarations, <CODE>warning</CODE> to allow implicit declarations
666
but to produce a warning when they occur, or <CODE>off</CODE> to prevent
667
implicit declarations and raise an error where they would normally
668
be used.<P>
669
(There are also equivalent command-line options to tcc of the form
670
<CODE>-X:implicit_func=</CODE><CODE>state</CODE>, where <CODE>state</CODE>
671
can be <CODE>check</CODE>, <CODE>warn</CODE> or <CODE>dont</CODE>.)<P>
672
This test assumes an added significance in API checking. If a programmer
673
wishes to check that a certain program uses nothing outside the POSIX
674
API, then implicitly declared functions are a potential danger area.
675
A function from outside POSIX could be used without being detected
676
because it has been implicitly declared. Therefore, the detection
677
of implicitly declared functions is vital to rigorous API checking.<P>
678
<A NAME=S28>
679
<H3>3.4.2  <A NAME=32>Function Parameters</H3>
680
Many systems pass function arguments of differing types in the same
681
way and programs are sometimes written to take advantage of this feature.
682
The checker has a number of options to resolve type mismatches which
683
may arise in this way and would otherwise be flagged as errors:<P>
684
<OL>
685
<LI><B>Type-type compatibility</B><P>
686
When comparing function prototypes for compatibility, the function
687
parameter types must be compared. If the parameter types would otherwise
688
be incompatible, they are treated as compatible if they have previously
689
been introduced with a type-type param ter compatibility pragma i.e.<P>
690
<PRE>
691
	#pragma TenDRA argument <EM>type-name</EM> as <EM>type-name</EM>
692
</PRE>
693
where <EM>type-name</EM> is the name of any type. This pragma is transitive
694
and the second type in the pragma is taken to be the final type of
695
the parameter. <P>
696
<LI><B>Type-ellipsis compatibility</B><P>
697
Two function prototypes with different numbers of arguments are compatible
698
if: <P>
699
<UL>
700
<LI>both prototypes have an ellipsis; <P>
701
<LI>each parameter type common to both prototypes is compatible;<P>
702
<LI>each extra parameter type in the prototype with more parameters,
703
is either specified in a type-ellipsis compatibility pragma or is
704
type-type compatible (see above) to a type that is specified in a
705
type-ellipsis compatibility.<P>
706
</UL>
707
Type-ellipsis compatibility is introduced using the pragma: <P>
708
<PRE>
709
	#pragma TenDRA argument <EM>type-name</EM> as ...
710
</PRE>
711
where again <CODE>type-name</CODE> is the name of any type.<P>
712
<LI><B>Ellipsis compatibility</B><P>
713
If, when comparing two function prototypes for compatibility, one
714
has an ellipsis and the other does not, but otherwise the two types
715
would be compatible, then if an `extra' ellipsis is allowed, the types
716
are treated as compatible. The pragma controlling ellipsis compatibility
717
is:<P>
718
<PRE>
719
	#pragma TenDRA extra ... <EM>permit</EM>
720
</PRE>
721
where <CODE>permit</CODE> may be <CODE>allow</CODE>, <CODE>disallow</CODE>
722
or <CODE>warning</CODE> as usual. <P>
723
</OL>
724
<P>
725
<P>
726
<A NAME=S29>
727
<H3>3.4.3  <A NAME=37>Incompatible promoted function arguments</H3>
728
Mixing the use of prototypes with old-fashioned function definitions
729
can result in incorrect code. For example, in the program below the
730
function argument promotion rules are applied to the definition of
731
f, making it incompatible with the earlier prototype (a is converted
732
to the integer promotion of char, i.e. int).<P>
733
<PRE>
734
	int f(char);
735
	int f(a)char a;{
736
		...
737
	}
738
</PRE>
739
An incompatible type error is raised in the default checking mode.
740
The check for incompatible types which arise from mixtures of prototyped
741
and non-prototyped function declarations and definitions is controlled
742
using: <P>
743
<CODE>#pragma TenDRA incompatible promoted function argument </CODE><EM>permit
744
</EM><P>
745
<CODE>Permit</CODE> may be replaced by <CODE>allow</CODE>, <CODE>warning</CODE>
746
or <CODE>disallow</CODE> as normal. The parameter type in the resulting
747
function type is the promoted parameter type.<P>
748
<A NAME=S30>
749
<H3>3.4.4  <A NAME=39>Incompatible type qualifiers</H3>
750
The declarations <P>
751
<PRE>
752
	const int a;
753
	int a;
754
</PRE>
755
are not compatible according to the ISO C standard because the qualifier,
756
const, is present in one declaration but not in the other. Similar
757
rules hold for volatile qualified types. By default, tchk produces
758
an error when declarations of the same object contain different type
759
qualifiers. The check is controlled using: <P>
760
<PRE>
761
	#pragma TenDRA incompatible type qualifier <EM>permit</EM>
762
</PRE>
763
where the options for <EM>permit</EM> are <CODE>allow</CODE>, <CODE>disallow
764
</CODE> or <CODE>warning</CODE>.<P>
765
<P>
766
<!-- FM pgf ignored -->
767
<HR>
768
<P><I>Part of the <A HREF="../index.html">TenDRA Web</A>.<BR>Crown
769
Copyright &copy; 1998.</I></P>
770
</BODY>
771
</HTML>