The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
build.h
Go to the documentation of this file.
1#pragma once
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18/**
19 * $Id: 29673151767740ff052b09be9b8d57dbdf030588 $
20 *
21 * @file include/build.h
22 * @brief Source control functions
23 *
24 * @copyright 2013 The FreeRADIUS server project
25 */
26
27#ifdef __cplusplus
28extern "C" {
29#endif
30
31/** For systems with an old version libc, define static_assert.
32 *
33 */
34#ifndef static_assert
35# if __STDC_VERSION__ < 202000
36# define static_assert _Static_assert
37# endif
38# else
39# include <assert.h>
40#endif
41
42/*
43 * Static analyzers don't notice or can't infer some properties
44 * of the code, and hence may give false positives. To deal with
45 * them, there is some conditionally compiled code in various
46 * places. The following lets the code change minimally if and
47 * when new static analyzers are added.
48 */
49#ifdef __clang_analyzer__
50#define STATIC_ANALYZER 1
51#endif
52#ifdef __COVERITY__
53#define STATIC_ANALYZER 1
54#endif
55
56/*
57 * Reduce spurious errors from static analyzers by having
58 * all paths that find the da to be NULL, result
59 * in program exit.
60 */
61#ifdef STATIC_ANALYZER
62# define WITH_VERIFY_PTR 1
63#endif
64
65/*
66 * GCC uses __SANITIZE_ADDRESS__, clang uses __has_feature, which
67 * GCC complains about.
68 */
69#ifndef __SANITIZE_ADDRESS__
70#ifdef __has_feature
71#if __has_feature(address_sanitizer)
72#define __SANITIZE_ADDRESS__ (1)
73#endif
74#endif
75#endif
76
77/*
78 * Basic headers we want everywhere
79 */
80#include <stdbool.h>
81#include <stdint.h>
82#include <stddef.h>
83#include <string.h>
84
85/*
86 * These are compile time options to toggle whether
87 * we're building with thread support.
88 *
89 * With EMSCRIPTEN threading support isn't guaranteed
90 * as many browsers have explicitly disabled support
91 * due to spectre attacks.
92 */
93#if (defined(__EMSCRIPTEN__) && defined(__EMSCRIPTEN_PTHREADS__)) || !defined(__EMSCRIPTEN__) && defined(HAVE_PTHREAD_H)
94# define HAVE_PTHREADS 1
95#endif
96
97/*
98 * GCC will sometimes define "unix" as well as "__unix",
99 * which gets confusing and is unnecessary.
100 */
101#undef unix
102
103/** Evaluates to +1 for a > b, and -1 for a < b
104 */
105#define CMP_PREFER_SMALLER(_a,_b) (((_a) > (_b)) - ((_a) < (_b)))
106
107/** Evaluates to -1 for a > b, and +1 for a < b
108 */
109#define CMP_PREFER_LARGER(_a,_b) (((_a) < (_b)) - ((_a) > (_b)))
110
111/** Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want _an_ ordering.
112 */
113#define CMP(_a, _b) CMP_PREFER_SMALLER(_a, _b)
114
115/** Return if the comparison is not 0 (is unequal)
116 *
117 * @param[in] _a pointer to first structure.
118 * @param[in] _b pointer to second structure.
119 * @param[in] _field within the structs to compare.
120 * @return The result of the comparison.
121 */
122#define CMP_RETURN(_a, _b, _field) \
123do { \
124 int8_t _ret = CMP((_a)->_field, (_b)->_field); \
125 if (_ret != 0) return _ret; \
126} while (0)
127
128/** memcmp function which has similar behaviour as strncmp
129 *
130 * @param[in] a First thing to compare.
131 * @param[in] b Second thing to compare.
132 * @param[in] a_len Length of first thing.
133 * @param[in] b_len Length of second thing.
134 * @return
135 * - +1 if a > b
136 * - 0 if a == b
137 * - -1 if a < b
138 */
139static inline int8_t memcmp_return(void const *a, void const *b, size_t a_len, size_t b_len)
140{
141 size_t cmp_len;
142 int8_t ret;
143
144 if (!a_len && b_len) return -1;
145 if (a_len && !b_len) return +1;
146 if (!a_len && !b_len) return 0;
147
148 cmp_len = (a_len < b_len) ? a_len : b_len;
149
150 ret = CMP(memcmp(a, b, cmp_len), 0); /* memcmp() can't be passed a NULL pointer */
151 if (ret != 0) return ret;
152
153 return CMP(a_len, b_len);
154}
155
156/** Return if the contents of the specified field is not identical between the specified structures
157 *
158 * @param[in] _a pointer to first structure.
159 * @param[in] _b pointer to second structure.
160 * @param[in] _field within the structs to compare.
161 * @param[in] _len_field within the structs, specifying the length of the data.
162 * @return The result of the comparison.
163 */
164#define MEMCMP_RETURN(_a, _b, _field, _len_field) \
165do { \
166 int8_t _ret = memcmp_return((_a)->_field, (_b)->_field, (_a)->_len_field, (_b)->_len_field); \
167 if (_ret != 0) return _ret; \
168} while (0)
169
170/** Return the comparison of two opaque fields of a structure
171 *
172 * @param[in] _a pointer to first structure.
173 * @param[in] _b pointer to second structure.
174 * @param[in] _field within the structs to compare.
175 * @param[in] _len_field within the structs, specifying the length of the data.
176 * @return The result of the comparison.
177 */
178#define MEMCMP_FIELDS(_a, _b, _field, _len_field) \
179 memcmp_return((_a)->_field, (_b)->_field, (_a)->_len_field, (_b)->_len_field)
180
181/** Remove const qualification from a pointer
182 *
183 * @param[in] _type The non-const version of the type.
184 * @param[in] _ptr to de-const.
185 */
186#define UNCONST(_type, _ptr) ((_type)((uintptr_t)(_ptr)))
187
188/** Typeof field
189 *
190 * @param[in] _type struct type containing the field.
191 * @param[in] _field to return the type of.
192 */
193#define typeof_field(_type, _field) __typeof__(((_type *)NULL)->_field)
194
195/** HEX concatenation macros
196 *
197 */
198#ifndef HEXIFY
199# define XHEXIFY4(b1,b2,b3,b4) (0x ## b1 ## b2 ## b3 ## b4)
200# define HEXIFY4(b1,b2,b3,b4) XHEXIFY4(b1, b2, b3, b4)
201
202# define XHEXIFY3(b1,b2,b3) (0x ## b1 ## b2 ## b3)
203# define HEXIFY3(b1,b2,b3) XHEXIFY3(b1, b2, b3)
204
205# define XHEXIFY2(b1,b2) (0x ## b1 ## b2)
206# define HEXIFY2(b1,b2) XHEXIFY2(b1, b2)
207
208# define XHEXIFY(b1) (0x ## b1)
209# define HEXIFY(b1) XHEXIFY(b1)
210#endif
211
212/** The ubiquitous stringify macros
213 *
214 */
215#define XSTRINGIFY(x) #x
216#define STRINGIFY(x) XSTRINGIFY(x)
217#define JOINSTR(x,y) XSTRINGIFY(x ## y)
218
219/** Join two values without stringifying
220 *
221 * Useful for calling different macros based on the output of
222*/
223#define _JOIN(x,y) x ## y
224#define JOIN(x,y) _JOIN(x,y)
225
226/** Helper for initialising arrays of string literals
227 */
228#define L(_str) { _str, sizeof(_str) - 1 }
229
230/** Fill macros for array initialisation
231 */
232#define F1(_idx, _val) [_idx] = _val
233#define F2(_idx, _val) F1(_idx, _val), F1(_idx + 1, _val)
234#define F4(_idx, _val) F2(_idx, _val), F2(_idx + 2, _val)
235#define F8(_idx, _val) F4(_idx, _val), F4(_idx + 4, _val)
236#define F16(_idx, _val) F8(_idx, _val), F8(_idx + 8, _val)
237#define F32(_idx, _val) F16(_idx, _val), F16(_idx + 16, _val)
238#define F64(_idx, _val) F32(_idx, _val), F32(_idx + 32, _val)
239#define F128(_idx, _val) F64(_idx, _val), F64(_idx + 64, _val)
240#define F256(_idx, _val) F128(_idx, _val), F128(_idx + 128, _val)
241
242/** Variadic macro framework
243 */
244
245/**
246 * The VA_NARG macro evaluates to the number of arguments that have been
247 * passed to it.
248 *
249 * Laurent Deniau, "__VA_NARG__," 17 January 2006, <comp.std.c> (29 November 2007).
250 */
251#define VA_ARG_N( \
252 _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
253 _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
254 _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
255 _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
256 _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
257 _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
258 _61,_62,_63,N,...) N
259
260#define VA_RSEQ_N() \
261 63,62,61,60, \
262 59,58,57,56,55,54,53,52,51,50, \
263 49,48,47,46,45,44,43,42,41,40, \
264 39,38,37,36,35,34,33,32,31,30, \
265 29,28,27,26,25,24,23,22,21,20, \
266 19,18,17,16,15,14,13,12,11,10, \
267 9,8,7,6,5,4,3,2,1,0
268
269#define _VA_NARG(...) VA_ARG_N(__VA_ARGS__)
270
271/** Return the number of variadic arguments up to 64
272 *
273 * @param[in] ... Variadic arguments to count.
274 */
275#define VA_NARG(...) _VA_NARG(__VA_ARGS__, VA_RSEQ_N())
276
277/** Expansion table for VA_STRINGIFY, one entry per supported argument count
278 */
279#define _VA_STR_1(_a) #_a
280#define _VA_STR_2(_a, ...) #_a, _VA_STR_1(__VA_ARGS__)
281#define _VA_STR_3(_a, ...) #_a, _VA_STR_2(__VA_ARGS__)
282#define _VA_STR_4(_a, ...) #_a, _VA_STR_3(__VA_ARGS__)
283#define _VA_STR_5(_a, ...) #_a, _VA_STR_4(__VA_ARGS__)
284#define _VA_STR_6(_a, ...) #_a, _VA_STR_5(__VA_ARGS__)
285#define _VA_STR_7(_a, ...) #_a, _VA_STR_6(__VA_ARGS__)
286#define _VA_STR_8(_a, ...) #_a, _VA_STR_7(__VA_ARGS__)
287#define _VA_STR_9(_a, ...) #_a, _VA_STR_8(__VA_ARGS__)
288#define _VA_STR_10(_a, ...) #_a, _VA_STR_9(__VA_ARGS__)
289#define _VA_STR_11(_a, ...) #_a, _VA_STR_10(__VA_ARGS__)
290#define _VA_STR_12(_a, ...) #_a, _VA_STR_11(__VA_ARGS__)
291#define _VA_STR_13(_a, ...) #_a, _VA_STR_12(__VA_ARGS__)
292#define _VA_STR_14(_a, ...) #_a, _VA_STR_13(__VA_ARGS__)
293#define _VA_STR_15(_a, ...) #_a, _VA_STR_14(__VA_ARGS__)
294#define _VA_STR_16(_a, ...) #_a, _VA_STR_15(__VA_ARGS__)
295#define _VA_STR_17(_a, ...) #_a, _VA_STR_16(__VA_ARGS__)
296#define _VA_STR_18(_a, ...) #_a, _VA_STR_17(__VA_ARGS__)
297#define _VA_STR_19(_a, ...) #_a, _VA_STR_18(__VA_ARGS__)
298#define _VA_STR_20(_a, ...) #_a, _VA_STR_19(__VA_ARGS__)
299#define _VA_STR_21(_a, ...) #_a, _VA_STR_20(__VA_ARGS__)
300#define _VA_STR_22(_a, ...) #_a, _VA_STR_21(__VA_ARGS__)
301#define _VA_STR_23(_a, ...) #_a, _VA_STR_22(__VA_ARGS__)
302#define _VA_STR_24(_a, ...) #_a, _VA_STR_23(__VA_ARGS__)
303#define _VA_STR_25(_a, ...) #_a, _VA_STR_24(__VA_ARGS__)
304#define _VA_STR_26(_a, ...) #_a, _VA_STR_25(__VA_ARGS__)
305#define _VA_STR_27(_a, ...) #_a, _VA_STR_26(__VA_ARGS__)
306#define _VA_STR_28(_a, ...) #_a, _VA_STR_27(__VA_ARGS__)
307#define _VA_STR_29(_a, ...) #_a, _VA_STR_28(__VA_ARGS__)
308#define _VA_STR_30(_a, ...) #_a, _VA_STR_29(__VA_ARGS__)
309#define _VA_STR_31(_a, ...) #_a, _VA_STR_30(__VA_ARGS__)
310#define _VA_STR_32(_a, ...) #_a, _VA_STR_31(__VA_ARGS__)
311
312#define _VA_STRINGIFY_N(_n, ...) _VA_STRINGIFY_I(_n, __VA_ARGS__)
313#define _VA_STRINGIFY_I(_n, ...) _VA_STR_ ## _n(__VA_ARGS__)
314
315/** Produce a comma separated list of string literals, one per variadic argument
316 *
317 * Each argument becomes the source text the caller wrote, so
318 * VA_STRINGIFY(request->reply, len + 1) expands to "request->reply", "len + 1".
319 * Argument counting reuses the VA_NARG table. Expansion is limited to 32 arguments.
320 *
321 * @param[in] ... Variadic arguments to stringify.
322 */
323#define VA_STRINGIFY(...) _VA_STRINGIFY_N(VA_NARG(__VA_ARGS__), __VA_ARGS__)
324
325
326/** Pass caller information to the function
327 *
328 */
329#ifndef NDEBUG
330# define NDEBUG_LOCATION_ARGS char const *file, int line,
331# define NDEBUG_LOCATION_VALS file, line,
332# define NDEBUG_LOCATION_FMT "%s[%d]: "
333# define NDEBUG_LOCATION_EXP __FILE__, __LINE__,
334# define NDEBUG_LOCATION_NONNULL(_num) ((_num) + 2)
335#else
336# define NDEBUG_LOCATION_ARGS
337# define NDEBUG_LOCATION_VALS
338# define NDEBUG_LOCATION_FMT ""
339# define NDEBUG_LOCATION_EXP
340# define NDEBUG_LOCATION_NONNULL(_num) (_num)
341#endif
342
343/** Check if a given variable is the _const or not
344 *
345 * @param[in] _type The base type of the variable (should not be marked const)
346 * @param[in] _var to check.
347 */
348#define IS_CONST(_type, _var) \
349 _Generic((_var), \
350 _type: false, \
351 const _type: true \
352 )
353
354/** Check if a given variable is the const or unconst version of a type
355 *
356 * Expands to _var if _var matches type, otherwise throws a compiler error.
357 *
358 * Useful for creating typesafe wrapper macros around functions which take
359 * void *s.
360 *
361 * @param[in] _type The base type of the variable (should not be marked const)
362 * @param[in] _var to check.
363 */
364#define IS_TYPE(_type, _var) \
365 _Generic((_var), \
366 _type: _var, \
367 const _type: _var \
368 )
369/*
370 * Mark variables as unused
371 */
372#define UNUSED_VAR(_x) ((void)_x)
373
374/** Pad _x to the next multiple of _y
375 *
376 */
377#define PAD(_x, _y) (_y - ((_x) % _y))
378
379/** Should be placed before the function return type
380 *
381 */
382#define NEVER_RETURNS _Noreturn
383#define HIDDEN CC_HINT(visibility("hidden"))
384#define UNUSED CC_HINT(unused)
385
386/** clang 10 doesn't recognised the FALL-THROUGH comment anymore
387 */
388#if (defined(__clang__) && (__clang_major__ >= 10)) || (defined(__GNUC__) && __GNUC__ >= 7)
389# define FALL_THROUGH CC_HINT(fallthrough)
390#else
391# define FALL_THROUGH ((void)0)
392#endif
393
394#ifndef NDEBUG
395# define NDEBUG_UNUSED
396#else
397# define NDEBUG_UNUSED UNUSED
398#endif
399
400#define BLANK_FORMAT " " /* GCC_LINT whines about empty formats */
401
402/*
403 * struct field size
404 */
405#define SIZEOF_MEMBER(_t, _m) sizeof(((_t *)0)->_m)
406#define NUM_ELEMENTS(_t) (sizeof((_t)) / sizeof((_t)[0]))
407
408/*
409 * For use with multidimensional arrays where
410 * the deeper array element has a size smaller than
411 * a pointer i.e. char foo[n][m]
412 */
413#define NUM_PTR_ELEMENTS(_t) (sizeof((_t)) / sizeof(void *))
414
415/*
416 * Type checking
417 */
418
419/** Check if two types are compatible (the C11 way)
420 *
421 * Expands to 1 if types are compatible, else 0.
422 *
423 * @param[in] _x pointer to check.
424 * @param[in] _t type to check compatibility with.
425 */
426#define IS_COMPATIBLE(_x, _t) _Generic(_x, _t:1, default: 0)
427
428/** Check if a field in a struct is compatible (the C11 way)
429 *
430 * Expands to 1 if types are compatible, else 0.
431 *
432 * @param[in] _s struct to check.
433 * @param[in] _f field in struct.
434 * @param[in] _t type to check compatibility with.
435 */
436#define IS_FIELD_COMPATIBLE(_s, _f, _t) _Generic(((_s *)0)->_f, _t:1, default: 0)
437
438/*
439 * Only use GCC __attribute__ if were building with a GCClike
440 * compiler.
441 */
442#ifdef __GNUC__
443# define CC_HINT(...) __attribute__((__VA_ARGS__))
444# define likely(_x) __builtin_expect((_x), 1)
445# define unlikely(_x) __builtin_expect((_x), 0)
446# define unpredictable(_x) __builtin_unpredictable((_x))
447# ifdef __clang__
448# define assume(_x) __builtin_assume(_x)
449# else
450# define assume(_x) do { if (!_x) __builtin_unreachable(); } while (0)
451# endif
452#else
453# define CC_HINT(...)
454# define likely(_x) _x
455# define unlikely(_x) _x
456# define unpredictable(_x) _x
457# define assume(_x)
458#endif
459
460/*
461 * GNU version check
462 */
463#ifdef __GNUC__
464 #ifndef __GNUC_PREREQ__
465 #define __GNUC_PREREQ__(x, y) \
466 ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
467 (__GNUC__ > (x)))
468 #endif
469#else
470 #define __GNUC_PREREQ__(x, y) 0
471#endif
472
473
474/*
475 * Macros to add pragmas
476 */
477#define PRAGMA(_x) _Pragma(#_x)
478
479/*
480 * Handle acquire/release macros
481 */
482#if defined(__clang__) && (__clang_major__ >= 13)
483# define CC_ACQUIRE_HANDLE(_tag) CC_HINT(acquire_handle(_tag))
484# define CC_USE_HANDLE(_tag) CC_HINT(use_handle(_tag))
485# define CC_RELEASE_HANDLE(_tag) CC_HINT(release_handle(_tag))
486#else
487# define CC_ACQUIRE_HANDLE(_tag)
488# define CC_USE_HANDLE(_tag)
489# define CC_RELEASE_HANDLE(_tag)
490#endif
491
492/*
493 * Disable various forms of ubsan
494 */
495#ifndef __has_feature
496# define __has_feature(_x) 0
497#endif
498#if defined(__clang__) && __has_feature(undefined_behavior_sanitizer)
499# define CC_NO_UBSAN(_sanitize) __attribute__((no_sanitize(STRINGIFY(_sanitize))))
500#elif __GNUC_PREREQ__(4, 9) && defined(__SANITIZE_UNDEFINED__)
501# define CC_NO_UBSAN(_sanitize) __attribute__((no_sanitize_undefined))
502#else
503# define CC_NO_UBSAN(_sanitize)
504#endif
505
506/*
507 * Disable sanitizers for undefined behaviour
508 */
509#if defined(__clang__)
510# define CC_NO_SANITIZE_UNDEFINED(_what) CC_HINT(no_sanitize(_what))
511#else
512# define CC_NO_SANITIZE_UNDEFINED(_what)
513#endif
514
515/*
516 * Macros for controlling warnings in GCC >= 4.2 and clang >= 2.8
517 */
518#if defined(__clang__) && ((__clang_major__ * 100) + __clang_minor__ >= 208)
519# define DIAG_UNKNOWN_PRAGMAS unknown-pragmas
520# define DIAG_PRAGMA(_x) PRAGMA(clang diagnostic _x)
521# define DIAG_OFF(_x) DIAG_PRAGMA(ignored JOINSTR(-W,_x))
522# define DIAG_ON(_x) DIAG_PRAGMA(warning JOINSTR(-W,_x))
523# define DIAG_PUSH() DIAG_PRAGMA(push)
524# define DIAG_POP() DIAG_PRAGMA(pop)
525#elif !defined(__clang__) && defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
526# define DIAG_UNKNOWN_PRAGMAS pragmas
527# define DIAG_PRAGMA(_x) PRAGMA(GCC diagnostic _x)
528# define DIAG_OFF(_x) DIAG_PRAGMA(ignored JOINSTR(-W,_x))
529# define DIAG_ON(_x) DIAG_PRAGMA(warning JOINSTR(-W,_x))
530# define DIAG_PUSH() DIAG_PRAGMA(push)
531# define DIAG_POP() DIAG_PRAGMA(pop)
532#else
533# define DIAG_UNKNOWN_PRAGMAS
534# define DIAG_OFF(_x)
535# define DIAG_ON(_x)
536# define DIAG_PUSH()
537# define DIAG_POP()
538#endif
539
540/*
541 * For dealing with APIs which are only deprecated in OSX (like the OpenSSL API)
542 */
543#ifdef __APPLE__
544# define USES_APPLE_DEPRECATED_API DIAG_OFF(deprecated-declarations)
545# define USES_APPLE_RST DIAG_ON(deprecated-declarations)
546#else
547# define USES_APPLE_DEPRECATED_API
548# define USES_APPLE_RST
549#endif
550
551#if defined(__GNUC__)
552/* force inclusion of ident keywords in the face of optimization */
553# define RCSID(id) static char const rcsid[] __attribute__ ((used)) = id;
554# define RCSIDH(h, id) static char const rcsid_ ## h [] __attribute__ ((used)) = id;
555#elif defined(__SUNPRO_C)
556/* put ident keyword into comment section (nicer than gcc way) */
557# define RCSID(id) PRAGMA(sun ident id)
558# define RCSIDH(h, id) PRAGMA(sun ident id)
559#else
560# define RCSID(id)
561# define RCSIDH(h, id)
562#endif
563#ifdef __cplusplus
564}
565#endif
566
567/*
568 * For closing macros which open a code block e.g. fr_rb_inorder_foreach
569 */
570#define endforeach }
571
572/* Explicitly evaluate and ignore an expression
573 *
574 * Why this macro?
575 * 1. gcc will warn about unused return values, even with the traditional cast to void.
576 * 2. There are cases in which an error case wants to clean up, but the function to
577 * clean up itself returns a status. In this context you don't care, but then you
578 * have the Scylla of unused return value and the Charybdis of Coverity complaining
579 * about an if that doesn't affect control flow. The following evaluates _expr and
580 * stores it in a variable marked as unused
581 * @param _expr The expression to be evaluated and ignored
582 * @param _type The type of the expression
583 */
584#define IGNORE(_expr, _type) \
585 do { \
586 _type ignored UNUSED = (_expr); \
587 } while (0)
588
589/** Force a compilation error if strncpy() is used.
590 *
591 */
592extern char *dont_use_strncpy(char *dst, char const *src, size_t len);
593#undef strncpy
594#define strncpy(_dst, _src, _len) dont_use_strncpy()
static int8_t memcmp_return(void const *a, void const *b, size_t a_len, size_t b_len)
memcmp function which has similar behaviour as strncmp
Definition build.h:139
char * dont_use_strncpy(char *dst, char const *src, size_t len)
Force a compilation error if strncpy() is used.
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:113