xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/check_arg.h (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
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