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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
#ifndef MACROS_H
#define MACROS_H
/* several useful macros, mostly from glib.h */
#ifndef NULL
# define NULL ((void *)0)
#endif
#ifndef FALSE
# define FALSE (!1)
#endif
#ifndef TRUE
# define TRUE (!FALSE)
#endif
#define N_ELEMENTS(arr) \
(sizeof(arr) / sizeof((arr)[0]))
#define MEM_ALIGN(size) \
(((size) + MEM_ALIGN_SIZE-1) & ~((size_t) MEM_ALIGN_SIZE-1))
#define PTR_OFFSET(ptr, offset) \
((void *) (((uintptr_t) (ptr)) + ((size_t) (offset))))
#define CONST_PTR_OFFSET(ptr, offset) \
((const void *) (((uintptr_t) (ptr)) + ((size_t) (offset))))
#define container_of(ptr, type, name) \
(type *)((char *)(ptr) - offsetof(type, name) + \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(ptr, &((type *) 0)->name))
/* Don't use simply MIN/MAX, as they're often defined elsewhere in include
files that are included after this file generating tons of warnings. */
#define I_MIN(a, b) (((a) < (b)) ? (a) : (b))
#define I_MAX(a, b) (((a) > (b)) ? (a) : (b))
/* make it easier to cast from/to pointers. assumes that
sizeof(uintptr_t) == sizeof(void *) and they're both the largest datatypes
that are allowed to be used. so, long long isn't safe with these. */
#define POINTER_CAST(i) \
((void *) (((uintptr_t)NULL) + (i)))
#define POINTER_CAST_TO(p, type) \
((type)(uintptr_t)(p))
/* Define VA_COPY() to do the right thing for copying va_list variables.
config.h may have already defined VA_COPY as va_copy or __va_copy. */
#ifndef VA_COPY
# if defined (__GNUC__) && defined (__PPC__) && \
(defined (_CALL_SYSV) || defined (_WIN32))
# define VA_COPY(ap1, ap2) (*(ap1) = *(ap2))
# elif defined (VA_COPY_AS_ARRAY)
# define VA_COPY(ap1, ap2) memmove ((ap1), (ap2), sizeof (va_list))
# else /* va_list is a pointer */
# define VA_COPY(ap1, ap2) ((ap1) = (ap2))
# endif /* va_list is a pointer */
#endif
/* Provide convenience macros for handling structure
* fields through their offsets.
*/
#define STRUCT_MEMBER_P(struct_p, struct_offset) \
((void *) ((char *) (struct_p) + (long) (struct_offset)))
#define CONST_STRUCT_MEMBER_P(struct_p, struct_offset) \
((const void *) ((const char *) (struct_p) + (long) (struct_offset)))
/* Provide simple macro statement wrappers:
STMT_START { statements; } STMT_END;
can be used as a single statement, as in
if (x) STMT_START { ... } STMT_END; else ... */
#if !(defined (STMT_START) && defined (STMT_END))
# define STMT_START do
# define STMT_END while (0)
#endif
/* Provide macros to feature the GCC function attribute. */
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
# define ATTRS_DEFINED
# define ATTR_FORMAT(format_idx, arg_idx) \
__attribute__((format (printf, format_idx, arg_idx)))
# define ATTR_FORMAT_ARG(arg_idx) \
__attribute__((format_arg (arg_idx)))
# define ATTR_SCANF(format_idx, arg_idx) \
__attribute__((format (scanf, format_idx, arg_idx)))
# define ATTR_STRFTIME(format_idx) \
__attribute__((format (strftime, format_idx, 0)))
# define ATTR_UNUSED __attribute__((unused))
# define ATTR_NORETURN __attribute__((noreturn))
# define ATTR_CONST __attribute__((const))
# define ATTR_PURE __attribute__((pure))
#else
# define ATTR_FORMAT(format_idx, arg_idx)
# define ATTR_FORMAT_ARG(arg_idx)
# define ATTR_SCANF(format_idx, arg_idx)
# define ATTR_STRFTIME(format_idx)
# define ATTR_UNUSED
# define ATTR_NORETURN
# define ATTR_CONST
# define ATTR_PURE
#endif
#ifdef HAVE_ATTR_NULL
# define ATTR_NULL(...) __attribute__((null(__VA_ARGS__)))
#else
# define ATTR_NULL(...)
#endif
#ifdef HAVE_ATTR_NOWARN_UNUSED_RESULT
# define ATTR_NOWARN_UNUSED_RESULT __attribute__((nowarn_unused_result))
#else
# define ATTR_NOWARN_UNUSED_RESULT
#endif
#if __GNUC__ > 2
# define ATTR_MALLOC __attribute__((malloc))
#else
# define ATTR_MALLOC
#endif
#if __GNUC__ > 3
/* GCC 4.0 and later */
# define ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
# define ATTR_SENTINEL __attribute__((sentinel))
#else
# define ATTR_WARN_UNUSED_RESULT
# define ATTR_SENTINEL
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
/* GCC 4.3 and later */
# define ATTR_HOT __attribute__((hot))
# define ATTR_COLD __attribute__((cold))
#else
# define ATTR_HOT
# define ATTR_COLD
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
/* GCC 4.9 and later */
# define ATTR_RETURNS_NONNULL __attribute__((returns_nonnull))
#else
# define ATTR_RETURNS_NONNULL
#endif
#ifdef HAVE_ATTR_DEPRECATED
# define ATTR_DEPRECATED(str) __attribute__((deprecated(str)))
#else
# define ATTR_DEPRECATED(str)
#endif
/* Macros to provide type safety for callback functions' context parameters.
This is used like:
// safe-api.h file:
typedef void safe_callback_t(struct foo *foo);
void safe_run(safe_callback_t *callback, void *context);
#define safe_run((safe_callback_t *)callback, \
TRUE ? context : CALLBACK_TYPECHECK(callback, void (*)(typeof(context))))
// safe-api.c file:
#undef safe_run
void safe_run(safe_callback_t *callback, void *context)
{
callback(context);
}
// in caller code:
static void callback(struct foo *foo);
struct foo *foo = ...;
safe_run(callback, foo);
The first step is to create the callback function in a normal way. Type
safety is added to it by creating a macro that overrides the function and
checks the callback type safety using CALLBACK_TYPECHECK().
The CALLBACK_TYPECHECK() macro works by giving a compiling failure if the
provided callback function isn't compatible with the specified function
type parameter. The function type parameter must use typeof(context) in
place of the "void *context" parameter, but otherwise use exactly the same
function type as what the callback is. The macro then casts the given
callback function into the type with "void *context".
*/
#ifdef HAVE_TYPE_CHECKS
# define CALLBACK_TYPECHECK(callback, type) \
(COMPILE_ERROR_IF_TRUE(!__builtin_types_compatible_p( \
typeof(&callback), type)) ? 1 : 0)
#else
# define CALLBACK_TYPECHECK(callback, type) 0
#endif
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0)) && \
!defined(__cplusplus) && !defined(STATIC_CHECKER)
# define COMPILE_ERROR_IF_TRUE(condition) \
(sizeof(char[1 - 2 * ((condition) ? 1 : 0)]) > 0 ? FALSE : FALSE)
#else
# define COMPILE_ERROR_IF_TRUE(condition) FALSE
#endif
#ifdef HAVE_TYPE_CHECKS
# define COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(_a, _b) \
COMPILE_ERROR_IF_TRUE( \
!__builtin_types_compatible_p(typeof(_a), typeof(_b)))
#define COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE(_a1, _a2, _b) \
COMPILE_ERROR_IF_TRUE( \
!__builtin_types_compatible_p(typeof(_a1), typeof(_b)) && \
!__builtin_types_compatible_p(typeof(_a2), typeof(_b)))
# define TYPE_CHECKS(return_type, checks, func) \
(FALSE ? (return_type)(checks) : (func))
#else
# define COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(_a, _b) 0
# define COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE(_a1, _a2, _b) 0
# define TYPE_CHECKS(return_type, checks, func) (func)
#endif
#if __GNUC__ > 2
# define unlikely(expr) (__builtin_expect((expr) ? 1 : 0, 0) != 0)
# define likely(expr) (__builtin_expect((expr) ? 1 : 0, 1) != 0)
#else
# define unlikely(expr) expr
# define likely(expr) expr
#endif
#if defined(__clang__) && ((__clang_major__ > 4) || (__clang_major__ == 3 && __clang_minor__ >= 9))
# define ATTR_UNSIGNED_WRAPS __attribute__((no_sanitize("integer")))
#else
# define ATTR_UNSIGNED_WRAPS
#endif
/* Provide macros for error handling. */
#ifdef DISABLE_ASSERTS
# define i_assert(expr)
#else
# define i_assert(expr) STMT_START{ \
if (unlikely(!(expr))) \
i_panic("file %s: line %d (%s): assertion failed: (%s)", \
__FILE__, \
__LINE__, \
__func__, \
#expr); }STMT_END
#endif
/* Convenience macro to test the versions of dovecot. */
#define DOVECOT_PREREQ(maj, min, micro) \
((DOVECOT_VERSION_MAJOR << 24) + \
(DOVECOT_VERSION_MINOR << 16) + \
DOVECOT_VERSION_MICRO >= ((maj) << 24) + ((min) << 16) + (micro))
#ifdef __cplusplus
# undef STATIC_ARRAY
# define STATIC_ARRAY
#endif
/* Convenience wrappers for initializing a struct with zeros, although it can
be used for replacing other memset()s also.
// NOTE: This is the correct way to zero the whole array
char arr[5]; i_zero(&arr);
// This will give compiler error (or zero only the first element):
char arr[5]; i_zero(arr);
*/
#define i_zero(p) \
memset(p, 0 + COMPILE_ERROR_IF_TRUE(sizeof(p) > sizeof(void *)), sizeof(*(p)))
#define i_zero_safe(p) \
safe_memset(p, 0 + COMPILE_ERROR_IF_TRUE(sizeof(p) > sizeof(void *)), sizeof(*(p)))
#define ST_CHANGED(st_a, st_b) \
((st_a).st_mtime != (st_b).st_mtime || \
ST_MTIME_NSEC(st_a) != ST_MTIME_NSEC(st_b) || \
(st_a).st_size != (st_b).st_size || \
(st_a).st_ino != (st_b).st_ino)
#ifdef HAVE_UNDEFINED_SANITIZER
# define ATTR_NO_SANITIZE(x) __attribute__((no_sanitize((x))))
#else
# define ATTR_NO_SANITIZE(x)
#endif
/* gcc and clang do this differently, see
https://gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/Common-Function-Attributes.html */
#ifdef HAVE_FSANITIZE_UNDEFINED
# ifdef __clang__
# define ATTR_NO_SANITIZE_UNDEFINED ATTR_NO_SANITIZE("undefined")
# else
# define ATTR_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
# endif
#else
# define ATTR_NO_SANITIZE_UNDEFINED
#endif
#ifdef HAVE_FSANITIZE_INTEGER
# define ATTR_NO_SANITIZE_INTEGER ATTR_NO_SANITIZE("integer")
# define ATTR_NO_SANITIZE_IMPLICIT_CONVERSION ATTR_NO_SANITIZE("implicit-conversion")
#else
# define ATTR_NO_SANITIZE_INTEGER
# define ATTR_NO_SANITIZE_IMPLICIT_CONVERSION
#endif
/* negate enumeration flags in a way that avoids implicit conversion */
#ifndef STATIC_CHECKER
# define ENUM_NEGATE(x) \
((unsigned int)(~(x)) + COMPILE_ERROR_IF_TRUE(sizeof((x)) > sizeof(int) || (x) < 0 || (x) > INT_MAX))
#else
/* clang scan-build keeps complaining about x > 2147483647 case, so disable the
sizeof check. */
# define ENUM_NEGATE(x) ((unsigned int)(~(x)))
#endif
#endif
|