summaryrefslogtreecommitdiffstats
path: root/src/util/check_arg.h
blob: 09f09326a4825df35e867fa131194f494115d39f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
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 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