#ifndef _CHECK_ARG_INCLUDED_ #define _CHECK_ARG_INCLUDED_ /*++ /* NAME /* check_arg 3h /* SUMMARY /* type checking/narrowing/widening for unprototyped arguments /* SYNOPSIS /* #include /* /* /* Example checking infrastructure for int, int *, const int *. */ /* CHECK_VAL_HELPER_DCL(tag, int); /* CHECK_PTR_HELPER_DCL(tag, int); /* CHECK_CPTR_HELPER_DCL(tag, int); /* /* /* Example variables with type int, int *, const int *. */ /* int int_val; /* int *int_ptr; /* const int *int_cptr; /* /* /* Example variadic function with type-flag arguments. */ /* func(FLAG_INT_VAL, CHECK_VAL(tag, int, int_val), /* FLAG_INT_PTR, CHECK_PTR(tag, int, int_ptr), /* FLAG_INT_CPTR, CHECK_CPTR(tag, int, int_cptr) /* FLAG_END); /* DESCRIPTION /* This module implements wrappers for unprototyped function /* arguments, to enable the same type checking, type narrowing, /* and type widening as for prototyped function arguments. The /* wrappers may also be useful in other contexts. /* /* Typically, these wrappers are hidden away in a per-module /* header file that is read by the consumers of that module. /* To protect consumers against name collisions between wrappers /* in different header files, wrappers should be called with /* a distinct per-module tag value. The tag syntax is that /* of a C identifier. /* /* Use CHECK_VAL(tag, type, argument) for arguments with a /* basic type: int, long, etc., and types defined with "typedef" /* where indirection is built into the type itself (for example, /* the result of "typedef int *foo" or function pointer /* typedefs). /* /* Use CHECK_PTR(tag, type, argument) for non-const pointer /* arguments, CHECK_CPTR(tag, type, argument) for const pointer /* arguments, and CHECK_PPTR(tag, type, argument) for pointer- /* to-pointer arguments. /* /* Use CHECK_*_HELPER_DCL(tag, type) to provide the /* checking infrastructure for all CHECK_*(tag, type, ...) /* instances with the same *, tag and type. Depending on /* the compilation environment, the infrastructure consists /* of an inline function definition or a dummy assignment /* target declaration. /* /* The compiler should report the following problems: /* .IP \(bu /* Const pointer argument where a non-const pointer is expected. /* .IP \(bu /* Pointer argument where a non-pointer is expected and /* vice-versa. /* .IP \(bu /* Pointer/pointer type mismatches except void/non-void pointers. /* Just like function prototypes, all CHECK_*PTR() wrappers /* cast their result to the desired type. /* .IP \(bu /* Non-constant non-pointer argument where a pointer is expected. /*. PP /* Just like function prototypes, the CHECK_*PTR() wrappers /* handle "bare" numerical constants by casting their argument /* to the desired pointer type. /* /* Just like function prototypes, the CHECK_VAL() wrapper /* cannot force the caller to specify a particular non-pointer /* type and casts its argument value to the desired type which /* may wider or narrower than the argument value. /* IMPLEMENTATION /* * Choose between an implementation based on inline functions (standardized * with C99) or conditional assignment (portable to older compilers, with * some caveats as discussed below). */ #ifndef NO_INLINE /* * Parameter checks expand into inline helper function calls. */ #define CHECK_VAL(tag, type, v) check_val_##tag##type(v) #define CHECK_PTR(tag, type, v) check_ptr_##tag##type(v) #define CHECK_CPTR(tag, type, v) check_cptr_##tag##type(v) #define CHECK_PPTR(tag, type, v) check_pptr_##tag##type(v) /* * Macros to instantiate the inline helper functions. */ #define CHECK_VAL_HELPER_DCL(tag, type) \ static inline type check_val_##tag##type(type v) { return v; } #define CHECK_PTR_HELPER_DCL(tag, type) \ static inline type *check_ptr_##tag##type(type *v) { return v; } #define CHECK_CPTR_HELPER_DCL(tag, type) \ static inline const type *check_cptr_##tag##type(const type *v) \ { return v; } #define CHECK_PPTR_HELPER_DCL(tag, type) \ static inline type **check_pptr_##tag##type(type **v) { return v; } #else /* NO_INLINE */ /* * Parameter checks expand into unreachable conditional assignments. * Inspired by OpenSSL's verified pointer check, our implementation also * detects const/non-const pointer conflicts, and it also supports * non-pointer expressions. */ #define CHECK_VAL(tag, type, v) ((type) (1 ? (v) : (CHECK_VAL_DUMMY(type) = (v)))) #define CHECK_PTR(tag, type, v) ((type *) (1 ? (v) : (CHECK_PTR_DUMMY(type) = (v)))) #define CHECK_CPTR(tag, type, v) \ ((const type *) (1 ? (v) : (CHECK_CPTR_DUMMY(type) = (v)))) #define CHECK_PPTR(tag, type, v) ((type **) (1 ? (v) : (CHECK_PPTR_DUMMY(type) = (v)))) /* * These macros instantiate assignment target declarations. Since the * assignment is made in unreachable code, the compiler "should" not emit * any references to those assignment targets. We use the "extern" class so * that gcc will not complain about unused variables. Using "extern" breaks * when a compiler does emit references to unreachable assignment targets. * Hopefully, those cases will be rare. */ #define CHECK_VAL_HELPER_DCL(tag, type) extern type CHECK_VAL_DUMMY(type) #define CHECK_PTR_HELPER_DCL(tag, type) extern type *CHECK_PTR_DUMMY(type) #define CHECK_CPTR_HELPER_DCL(tag, type) extern const type *CHECK_CPTR_DUMMY(type) #define CHECK_PPTR_HELPER_DCL(tag, type) extern type **CHECK_PPTR_DUMMY(type) /* * The actual dummy assignment target names. */ #define CHECK_VAL_DUMMY(type) check_val_dummy_##type #define CHECK_PTR_DUMMY(type) check_ptr_dummy_##type #define CHECK_CPTR_DUMMY(type) check_cptr_dummy_##type #define CHECK_PPTR_DUMMY(type) check_pptr_dummy_##type #endif /* NO_INLINE */ /* LICENSE /* .ad /* .fi /* The Secure Mailer license must be distributed with this software. /* AUTHOR(S) /* Wietse Venema /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /*--*/ #endif