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