Home | History | Annotate | Line # | Download | only in util
      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