Postfix3.3.1
check_arg.h
[詳解]
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 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