forked from acassen/keepalived
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalign.h
111 lines (101 loc) · 5.06 KB
/
align.h
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
/*
* Soft: Keepalived is a failover program for the LVS project
* <www.linuxvirtualserver.org>. It monitor & manipulate
* a loadbalanced server pool using multi-layer checks.
*
* Part: align.h include file.
*
* Author: Quentin Armitage <[email protected]>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Copyright (C) 2020-2020 Alexandre Cassen, <[email protected]>
*/
#ifndef _ALIGN_H
#define _ALIGN_H
#include "config.h"
#ifdef CHECK_CAST_ALIGN
#include "logger.h"
#endif
/* PTR_CAST and PTR_CAST_CONST should be used for all casts of pointers.
*
* PTR_CAST and PTR_CAST_CONST serve several purposes.
*
* 1) On 32 bit ARM systems which don't support unaligned memory access, configure
* will have defined CAST_VIA_VOID to avoid the compiler spewing out 1000s of
* "cast increases required alignment of target type" warnings which are caused
* due to the char * used in the cast possibly not being aligned for the pointer
* being cast to. CAST_VIA_VOID merely means that the char * is first cast to a
* void * which is then cast to the pointer of the type required. Casting via a
* void * should not alter the code produced by the compiler, since the initial
* pointer (char *) only has 1 byte alignment.
*
* This still leaves the problem that, if the keepalived code is not correct, there
* may be an unaligned pointer being used. See 2) below for how this is dealt with.
*
* On systems which do allow unaligned memory access, the warnings generated by
* not using a void * can be generated by using configure options:
* --enable-strict-cast-align --disable-cast-via-void
*
* 2) As identified in 1) above, there is a need to be able to ensure that there
* are no unaligned casts, both for performance reasons on sytems which do allow
* unaligned casts, and to ensure that there are not alignment traps, or worse
* still incorrect values returned (which happens with ARMv5) from unaligned reads.
*
* For this reason there is a configure option --enable-cast-align-checks which
* defines CHECK_CAST_ALIGN. This causes PTR_CAST and PTR_CAST_CONST to generate
* run-time code to check that casts made via PTR_CAST and PRT_CAST_CONST are
* properly aligned, and logs a message if they are not. The checks work on any
* architecture, whether unaligned memory access works or not, and so can be
* performed on Intel x86_64, aarch64 etc.
*
* Developers should periodically build with this option enabled and then run
* keepalived to check that there are no unaligned casts. 22 such instances of
* unaligned char arrays being cast to structure pointers with greater alignment
* were found when this check was first added.
*
* 3) Other cast checks can be added later by simply adding further definitions for
* PTR_CAST and PTR_CAST_CONST, probably just by adding a further definition of
* PTR_CAST_ALL.
*/
#ifdef CAST_VIA_VOID
#define __CAST_PTR(__const) (__const void *)
#define PTR_CAST_ASSIGN (void *)
#define PTR_CAST_ASSIGN_CONST (const void *)
#else
#define __CAST_PTR(__const)
#define PTR_CAST_ASSIGN
#define PTR_CAST_ASSIGN_CONST
#endif
#ifdef CHECK_CAST_ALIGN
#define PTR_CAST_ALL(__type, __ptr, __const) ({ \
__const void *sav_ptr = __ptr; \
if ((long)sav_ptr % __alignof__(__type)) \
log_message(LOG_INFO, "Alignment error - (" #__type " *)(" #__ptr ") - alignment %zu, address %p", __alignof__(__type), sav_ptr); \
(__const __type *) __CAST_PTR(__const) (sav_ptr); \
})
#define PTR_CAST2_ALL(__type, __type1, __ptr, __field, __const) ({ \
__const void *sav_ptr1 = __ptr; \
if ((long)sav_ptr1 % __alignof__(__type1)) \
printf("Alignment error - (" #__type1 " *)(" #__ptr ") - alignment %zu, address %p", __alignof__(__type1), sav_ptr1); \
PTR_CAST_ALL(__type, &(((__const __type1 *) __CAST_PTR(__const) (sav_ptr1))->__field), __const);\
})
#else
#define PTR_CAST_ALL(__type, __ptr, __const) \
({ (__const __type *) __CAST_PTR(__const) (__ptr); })
#define PTR_CAST2_ALL(__type, __type1, __ptr, __field, __const) \
({ (__const __type *) __CAST_PTR(__const) &((__const __type1 *) __CAST_PTR(__const) (__ptr))->__field; })
#endif
#define PTR_CAST(__type, __ptr) PTR_CAST_ALL(__type, __ptr,)
#define PTR_CAST_CONST(__type, __ptr) PTR_CAST_ALL(__type, __ptr, const)
#define PTR_CAST2(__type, __type1, __ptr, __field) PTR_CAST2_ALL(__type, __type1, __ptr, __field,)
#define PTR_CAST2_CONST(__type, __type1, __ptr, __field) PTR_CAST2_ALL(__type, __type1, __ptr, __field, const)
#endif