diff options
Diffstat (limited to 'src/util/check_arg.h')
-rw-r--r-- | src/util/check_arg.h | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/util/check_arg.h b/src/util/check_arg.h new file mode 100644 index 0000000..3a83895 --- /dev/null +++ b/src/util/check_arg.h @@ -0,0 +1,157 @@ +#ifndef _CHECK_ARG_INCLUDED_ +#define _CHECK_ARG_INCLUDED_ + +/*++ +/* NAME +/* check_arg 3h +/* SUMMARY +/* type checking/narrowing/widening for unprototyped arguments +/* SYNOPSIS +/* #include <check_arg.h> +/* +/* /* 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 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 |