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