1 #ifndef _CHECK_ARG_INCLUDED_
2 #define _CHECK_ARG_INCLUDED_
3 
4 /*++
5 /* NAME
6 /*	check_arg 3h
7 /* SUMMARY
8 /*	type checking/narrowing/widening for unprototyped arguments
9 /* SYNOPSIS
10 /*	#include <check_arg.h>
11 /*
12 /*	/* Example checking infrastructure for int, int *, const int *. */
13 /*	CHECK_VAL_HELPER_DCL(tag, int);
14 /*	CHECK_PTR_HELPER_DCL(tag, int);
15 /*	CHECK_CPTR_HELPER_DCL(tag, int);
16 /*
17 /*	/* Example variables with type int, int *, const int *. */
18 /*	int int_val;
19 /*	int *int_ptr;
20 /*	const int *int_cptr;
21 /*
22 /*	/* Example variadic function with type-flag arguments. */
23 /*	func(FLAG_INT_VAL, CHECK_VAL(tag, int, int_val),
24 /*	     FLAG_INT_PTR, CHECK_PTR(tag, int, int_ptr),
25 /*	     FLAG_INT_CPTR, CHECK_CPTR(tag, int, int_cptr)
26 /*	     FLAG_END);
27 /* DESCRIPTION
28 /*	This module implements wrappers for unprototyped function
29 /*	arguments, to enable the same type checking, type narrowing,
30 /*	and type widening as for prototyped function arguments. The
31 /*	wrappers may also be useful in other contexts.
32 /*
33 /*	Typically, these wrappers are hidden away in a per-module
34 /*	header file that is read by the consumers of that module.
35 /*	To protect consumers against name collisions between wrappers
36 /*	in different header files, wrappers should be called with
37 /*	a distinct per-module tag value.  The tag syntax is that
38 /*	of a C identifier.
39 /*
40 /*	Use CHECK_VAL(tag, type, argument) for arguments with a
41 /*	basic type: int, long, etc., and types defined with "typedef"
42 /*	where indirection is built into the type itself (for example,
43 /*	the result of "typedef int *foo" or function pointer
44 /*	typedefs).
45 /*
46 /*	Use CHECK_PTR(tag, type, argument) for non-const pointer
47 /*	arguments, CHECK_CPTR(tag, type, argument) for const pointer
48 /*	arguments, and CHECK_PPTR(tag, type, argument) for pointer-
49 /*	to-pointer arguments.
50 /*
51 /*	Use CHECK_*_HELPER_DCL(tag, type) to provide the
52 /*	checking infrastructure for all CHECK_*(tag, type, ...)
53 /*	instances with the same *, tag and type. Depending on
54 /*	the compilation environment, the infrastructure consists
55 /*	of an inline function definition or a dummy assignment
56 /*	target declaration.
57 /*
58 /*	The compiler should report the following problems:
59 /* .IP \(bu
60 /*	Const pointer argument where a non-const pointer is expected.
61 /* .IP \(bu
62 /*	Pointer argument where a non-pointer is expected and
63 /*	vice-versa.
64 /* .IP \(bu
65 /*	Pointer/pointer type mismatches except void/non-void pointers.
66 /*	Just like function prototypes, all CHECK_*PTR() wrappers
67 /*	cast their result to the desired type.
68 /* .IP \(bu
69 /*	Non-constant non-pointer argument where a pointer is expected.
70 /*. PP
71 /*	Just like function prototypes, the CHECK_*PTR() wrappers
72 /*	handle "bare" numerical constants by casting their argument
73 /*	to the desired pointer type.
74 /*
75 /*	Just like function prototypes, the CHECK_VAL() wrapper
76 /*	cannot force the caller to specify a particular non-pointer
77 /*	type and casts its argument value to the desired type which
78 /*	may wider or narrower than the argument value.
79 /* IMPLEMENTATION
80 
81  /*
82   * Choose between an implementation based on inline functions (standardized
83   * with C99) or conditional assignment (portable to older compilers, with
84   * some caveats as discussed below).
85   */
86 #ifndef NO_INLINE
87 
88  /*
89   * Parameter checks expand into inline helper function calls.
90   */
91 #define CHECK_VAL(tag, type, v) check_val_##tag##type(v)
92 #define CHECK_PTR(tag, type, v) check_ptr_##tag##type(v)
93 #define CHECK_CPTR(tag, type, v) check_cptr_##tag##type(v)
94 #define CHECK_PPTR(tag, type, v) check_pptr_##tag##type(v)
95 
96  /*
97   * Macros to instantiate the inline helper functions.
98   */
99 #define CHECK_VAL_HELPER_DCL(tag, type) \
100 	static inline type check_val_##tag##type(type v) { return v; }
101 #define CHECK_PTR_HELPER_DCL(tag, type) \
102 	static inline type *check_ptr_##tag##type(type *v) { return v; }
103 #define CHECK_CPTR_HELPER_DCL(tag, type) \
104 	static inline const type *check_cptr_##tag##type(const type *v) \
105 	    { return v; }
106 #define CHECK_PPTR_HELPER_DCL(tag, type) \
107 	static inline type **check_pptr_##tag##type(type **v) { return v; }
108 
109 #else					/* NO_INLINE */
110 
111  /*
112   * Parameter checks expand into unreachable conditional assignments.
113   * Inspired by OpenSSL's verified pointer check, our implementation also
114   * detects const/non-const pointer conflicts, and it also supports
115   * non-pointer expressions.
116   */
117 #define CHECK_VAL(tag, type, v) ((type) (1 ? (v) : (CHECK_VAL_DUMMY(type) = (v))))
118 #define CHECK_PTR(tag, type, v) ((type *) (1 ? (v) : (CHECK_PTR_DUMMY(type) = (v))))
119 #define CHECK_CPTR(tag, type, v) \
120 	((const type *) (1 ? (v) : (CHECK_CPTR_DUMMY(type) = (v))))
121 #define CHECK_PPTR(tag, type, v) ((type **) (1 ? (v) : (CHECK_PPTR_DUMMY(type) = (v))))
122 
123  /*
124   * These macros instantiate assignment target declarations. Since the
125   * assignment is made in unreachable code, the compiler "should" not emit
126   * any references to those assignment targets. We use the "extern" class so
127   * that gcc will not complain about unused variables. Using "extern" breaks
128   * when a compiler does emit references to unreachable assignment targets.
129   * Hopefully, those cases will be rare.
130   */
131 #define CHECK_VAL_HELPER_DCL(tag, type) extern type CHECK_VAL_DUMMY(type)
132 #define CHECK_PTR_HELPER_DCL(tag, type) extern type *CHECK_PTR_DUMMY(type)
133 #define CHECK_CPTR_HELPER_DCL(tag, type) extern const type *CHECK_CPTR_DUMMY(type)
134 #define CHECK_PPTR_HELPER_DCL(tag, type) extern type **CHECK_PPTR_DUMMY(type)
135 
136  /*
137   * The actual dummy assignment target names.
138   */
139 #define CHECK_VAL_DUMMY(type) check_val_dummy_##type
140 #define CHECK_PTR_DUMMY(type) check_ptr_dummy_##type
141 #define CHECK_CPTR_DUMMY(type) check_cptr_dummy_##type
142 #define CHECK_PPTR_DUMMY(type) check_pptr_dummy_##type
143 
144 #endif					/* NO_INLINE */
145 
146 /* LICENSE
147 /* .ad
148 /* .fi
149 /*	The Secure Mailer license must be distributed with this software.
150 /* AUTHOR(S)
151 /*	Wietse Venema
152 /*	IBM T.J. Watson Research
153 /*	P.O. Box 704
154 /*	Yorktown Heights, NY 10598, USA
155 /*--*/
156 
157 #endif
158