Skip to content

Commit 24efaa4

Browse files
authored
Fix various alignment violations (#32513)
The C standard forbids accessing pointers that are not sufficiently aligned for their base type under the penalty of undefined behavior. On most architectures we support, this doesn't make a difference (except if the compiler tries to SIMD things), but it does matter on some (e.g. SAFE_HEAP mode in wasm), so make some progress on using the proper unaligned accessors in various places that use underaligned pointers.
1 parent c690489 commit 24efaa4

File tree

9 files changed

+179
-143
lines changed

9 files changed

+179
-143
lines changed

src/flisp/cvalues.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ static int cvalue_##ctype##_init(fl_context_t *fl_ctx, fltype_t *type, \
242242
else { \
243243
return 1; \
244244
} \
245-
*((fl_##ctype##_t*)dest) = n; \
245+
memcpy(jl_assume_aligned(dest, sizeof(void*)), &n, \
246+
sizeof(fl_##ctype##_t)); \
246247
return 0; \
247248
}
248249
num_init(int8, int32, T_INT8)

src/flisp/flisp.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -990,11 +990,12 @@ static uint32_t process_keys(fl_context_t *fl_ctx, value_t kwtable,
990990
((int16_t) \
991991
((((int16_t)a[0])<<0) | \
992992
(((int16_t)a[1])<<8)))
993-
#define PUT_INT32(a,i) (*(int32_t*)(a) = bswap_32((int32_t)(i)))
993+
#define PUT_INT32(a,i) jl_store_unaligned_i32((void*)a,
994+
(uint32_t)bswap_32((int32_t)(i)))
994995
#else
995-
#define GET_INT32(a) (*(int32_t*)a)
996-
#define GET_INT16(a) (*(int16_t*)a)
997-
#define PUT_INT32(a,i) (*(int32_t*)(a) = (int32_t)(i))
996+
#define GET_INT32(a) (int32_t)jl_load_unaligned_i32((void*)a)
997+
#define GET_INT16(a) (int16_t)jl_load_unaligned_i16((void*)a)
998+
#define PUT_INT32(a,i) jl_store_unaligned_i32((void*)a, (uint32_t)(i))
998999
#endif
9991000
#define SWAP_INT32(a) (*(int32_t*)(a) = bswap_32(*(int32_t*)(a)))
10001001
#define SWAP_INT16(a) (*(int16_t*)(a) = bswap_16(*(int16_t*)(a)))

src/julia.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@
2020
#include <setjmp.h>
2121
#ifndef _OS_WINDOWS_
2222
# define jl_jmp_buf sigjmp_buf
23-
# if defined(_CPU_ARM_) || defined(_CPU_PPC_)
23+
# if defined(_CPU_ARM_) || defined(_CPU_PPC_) || defined(_CPU_WASM_)
2424
# define MAX_ALIGN 8
2525
# elif defined(_CPU_AARCH64_)
2626
// int128 is 16 bytes aligned on aarch64
2727
# define MAX_ALIGN 16
28+
# elif defined(_P64)
29+
// Generically we assume MAX_ALIGN is sizeof(void*)
30+
# define MAX_ALIGN 8
2831
# else
29-
# define MAX_ALIGN sizeof(void*)
32+
# define MAX_ALIGN 4
3033
# endif
3134
#else
3235
# include "win32_ucontext.h"

src/julia_internal.h

Lines changed: 3 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@
1313
#define sleep(x) Sleep(1000*x)
1414
#endif
1515

16-
#ifdef __has_builtin
17-
# define jl_has_builtin(x) __has_builtin(x)
18-
#else
19-
# define jl_has_builtin(x) 0
20-
#endif
21-
2216
#if defined(__has_feature)
2317
#if __has_feature(address_sanitizer)
2418
#define JL_ASAN_ENABLED // Clang flavor
@@ -57,42 +51,6 @@
5751
# endif
5852
#endif
5953

60-
#if jl_has_builtin(__builtin_assume)
61-
#define jl_assume(cond) (__extension__ ({ \
62-
__typeof__(cond) cond_ = (cond); \
63-
__builtin_assume(!!(cond_)); \
64-
cond_; \
65-
}))
66-
#elif defined(_COMPILER_MICROSOFT_) && defined(__cplusplus)
67-
template<typename T>
68-
static inline T
69-
jl_assume(T v)
70-
{
71-
__assume(!!v);
72-
return v;
73-
}
74-
#elif defined(_COMPILER_INTEL_)
75-
#define jl_assume(cond) (__extension__ ({ \
76-
__typeof__(cond) cond_ = (cond); \
77-
__assume(!!(cond_)); \
78-
cond_; \
79-
}))
80-
#elif defined(__GNUC__)
81-
static inline void jl_assume_(int cond)
82-
{
83-
if (!cond) {
84-
__builtin_unreachable();
85-
}
86-
}
87-
#define jl_assume(cond) (__extension__ ({ \
88-
__typeof__(cond) cond_ = (cond); \
89-
jl_assume_(!!(cond_)); \
90-
cond_; \
91-
}))
92-
#else
93-
#define jl_assume(cond) (cond)
94-
#endif
95-
9654
#if defined(__GLIBC__) && defined(JULIA_HAS_IFUNC_SUPPORT)
9755
// Make sure both the compiler and the glibc supports it.
9856
// Only enable this on known working glibc versions.
@@ -179,7 +137,7 @@ void gc_sweep_sysimg(void);
179137
static const int jl_gc_sizeclasses[] = {
180138
#ifdef _P64
181139
8,
182-
#elif defined(_CPU_ARM_) || defined(_CPU_PPC_)
140+
#elif MAX_ALIGN == 8
183141
// ARM and PowerPC have max alignment of 8,
184142
// make sure allocation of size 8 has that alignment.
185143
4, 8,
@@ -218,7 +176,7 @@ STATIC_INLINE int jl_gc_alignment(size_t sz)
218176
#ifdef _P64
219177
(void)sz;
220178
return 16;
221-
#elif defined(_CPU_ARM_) || defined(_CPU_PPC_)
179+
#elif MAX_ALIGN == 8
222180
return sz <= 4 ? 8 : 16;
223181
#else
224182
// szclass 8
@@ -246,7 +204,7 @@ STATIC_INLINE uint8_t JL_CONST_FUNC jl_gc_szclass(unsigned sz)
246204
if (sz <= 8)
247205
return 0;
248206
const int N = 0;
249-
#elif defined(_CPU_ARM_) || defined(_CPU_PPC_)
207+
#elif MAX_ALIGN == 8
250208
if (sz <= 8)
251209
return (sz >= 4 ? 1 : 0);
252210
const int N = 1;
@@ -1061,32 +1019,6 @@ void jl_register_fptrs(uint64_t sysimage_base, const struct _jl_sysimg_fptrs_t *
10611019

10621020
extern arraylist_t partial_inst;
10631021

1064-
#if jl_has_builtin(__builtin_assume_aligned) || defined(_COMPILER_GCC_)
1065-
#define jl_assume_aligned(ptr, align) __builtin_assume_aligned(ptr, align)
1066-
#elif defined(_COMPILER_INTEL_)
1067-
#define jl_assume_aligned(ptr, align) (__extension__ ({ \
1068-
__typeof__(ptr) ptr_ = (ptr); \
1069-
__assume_aligned(ptr_, align); \
1070-
ptr_; \
1071-
}))
1072-
#elif defined(__GNUC__)
1073-
#define jl_assume_aligned(ptr, align) (__extension__ ({ \
1074-
__typeof__(ptr) ptr_ = (ptr); \
1075-
jl_assume(((uintptr_t)ptr) % (align) == 0); \
1076-
ptr_; \
1077-
}))
1078-
#elif defined(__cplusplus)
1079-
template<typename T>
1080-
static inline T
1081-
jl_assume_aligned(T ptr, unsigned align)
1082-
{
1083-
(void)jl_assume(((uintptr_t)ptr) % align == 0);
1084-
return ptr;
1085-
}
1086-
#else
1087-
#define jl_assume_aligned(ptr, align) (ptr)
1088-
#endif
1089-
10901022
#if jl_has_builtin(__builtin_unreachable) || defined(_COMPILER_GCC_) || defined(_COMPILER_INTEL_)
10911023
# define jl_unreachable() __builtin_unreachable()
10921024
#else

src/julia_threads.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ typedef struct {
100100
// variables for allocating objects from pools
101101
#ifdef _P64
102102
# define JL_GC_N_POOLS 41
103-
#elif defined(_CPU_ARM_) || defined(_CPU_PPC_)
103+
#elif MAX_ALIGN == 8
104104
# define JL_GC_N_POOLS 42
105105
#else
106106
# define JL_GC_N_POOLS 43

src/staticdata.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ static void jl_write_gv_ints(jl_serializer_state *s)
891891

892892
static inline uint32_t load_uint32(uintptr_t *base)
893893
{
894-
uint32_t v = **(uint32_t**)base;
894+
uint32_t v = jl_load_unaligned_i32((void*)*base);
895895
*base += 4;
896896
return v;
897897
}

src/support/dtypes.h

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,74 @@
131131
# define JL_ATTRIBUTE_ALIGN_PTRSIZE(x)
132132
#endif
133133

134+
#ifdef __has_builtin
135+
# define jl_has_builtin(x) __has_builtin(x)
136+
#else
137+
# define jl_has_builtin(x) 0
138+
#endif
139+
140+
#if jl_has_builtin(__builtin_assume)
141+
#define jl_assume(cond) (__extension__ ({ \
142+
__typeof__(cond) cond_ = (cond); \
143+
__builtin_assume(!!(cond_)); \
144+
cond_; \
145+
}))
146+
#elif defined(_COMPILER_MICROSOFT_) && defined(__cplusplus)
147+
template<typename T>
148+
static inline T
149+
jl_assume(T v)
150+
{
151+
__assume(!!v);
152+
return v;
153+
}
154+
#elif defined(_COMPILER_INTEL_)
155+
#define jl_assume(cond) (__extension__ ({ \
156+
__typeof__(cond) cond_ = (cond); \
157+
__assume(!!(cond_)); \
158+
cond_; \
159+
}))
160+
#elif defined(__GNUC__)
161+
static inline void jl_assume_(int cond)
162+
{
163+
if (!cond) {
164+
__builtin_unreachable();
165+
}
166+
}
167+
#define jl_assume(cond) (__extension__ ({ \
168+
__typeof__(cond) cond_ = (cond); \
169+
jl_assume_(!!(cond_)); \
170+
cond_; \
171+
}))
172+
#else
173+
#define jl_assume(cond) (cond)
174+
#endif
175+
176+
#if jl_has_builtin(__builtin_assume_aligned) || defined(_COMPILER_GCC_)
177+
#define jl_assume_aligned(ptr, align) __builtin_assume_aligned(ptr, align)
178+
#elif defined(_COMPILER_INTEL_)
179+
#define jl_assume_aligned(ptr, align) (__extension__ ({ \
180+
__typeof__(ptr) ptr_ = (ptr); \
181+
__assume_aligned(ptr_, align); \
182+
ptr_; \
183+
}))
184+
#elif defined(__GNUC__)
185+
#define jl_assume_aligned(ptr, align) (__extension__ ({ \
186+
__typeof__(ptr) ptr_ = (ptr); \
187+
jl_assume(((uintptr_t)ptr) % (align) == 0); \
188+
ptr_; \
189+
}))
190+
#elif defined(__cplusplus)
191+
template<typename T>
192+
static inline T
193+
jl_assume_aligned(T ptr, unsigned align)
194+
{
195+
(void)jl_assume(((uintptr_t)ptr) % align == 0);
196+
return ptr;
197+
}
198+
#else
199+
#define jl_assume_aligned(ptr, align) (ptr)
200+
#endif
201+
134202
typedef int bool_t;
135203
typedef unsigned char byte_t; /* 1 byte */
136204

@@ -221,12 +289,35 @@ typedef enum { T_INT8, T_UINT8, T_INT16, T_UINT16, T_INT32, T_UINT32,
221289
#define JL_UNUSED
222290
#endif
223291

292+
STATIC_INLINE double jl_load_unaligned_f64(const void *ptr) JL_NOTSAFEPOINT
293+
{
294+
double val;
295+
memcpy(&val, ptr, sizeof(double));
296+
return val;
297+
}
298+
224299
STATIC_INLINE uint64_t jl_load_unaligned_i64(const void *ptr) JL_NOTSAFEPOINT
225300
{
226301
uint64_t val;
227-
memcpy(&val, ptr, 8);
302+
memcpy(&val, ptr, sizeof(uint64_t));
303+
return val;
304+
}
305+
306+
STATIC_INLINE double jl_load_ptraligned_f64(const void *ptr) JL_NOTSAFEPOINT
307+
{
308+
double val;
309+
memcpy(&val, jl_assume_aligned(ptr, sizeof(void*)), sizeof(double));
310+
return val;
311+
}
312+
313+
STATIC_INLINE uint64_t jl_load_ptraligned_i64(const void *ptr) JL_NOTSAFEPOINT
314+
{
315+
uint64_t val;
316+
memcpy(&val, jl_assume_aligned(ptr, sizeof(void*)), sizeof(uint64_t));
228317
return val;
229318
}
319+
320+
230321
STATIC_INLINE uint32_t jl_load_unaligned_i32(const void *ptr) JL_NOTSAFEPOINT
231322
{
232323
uint32_t val;

src/support/ios.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,23 @@ typedef enum { bst_none, bst_rd, bst_wr } bufstate_t;
2222
#define IOS_INLSIZE 54
2323
#define IOS_BUFSIZE 131072
2424

25-
typedef struct {
25+
#ifdef _P64
26+
#define ON_P64(x) x
27+
#else
28+
#define ON_P64(x)
29+
#endif
30+
31+
// We allow ios_t as a cvalue in flisp, which only guarantees pointer
32+
// alignment. Make sure the compiler knows.
33+
JL_ATTRIBUTE_ALIGN_PTRSIZE(typedef struct {
2634
// the state only indicates where the underlying file position is relative
2735
// to the buffer. reading: at the end. writing: at the beginning.
2836
// in general, you can do any operation in any state.
2937
char *buf; // start of buffer
3038

3139
int errcode;
3240

33-
#ifdef _P64
34-
int _pad_bm; // put bm at same offset as type field of uv_stream_s
35-
#endif
41+
ON_P64(int _pad_bm;) // put bm at same offset as type field of uv_stream_s
3642
bufmode_t bm; //
3743
bufstate_t state;
3844

@@ -70,7 +76,9 @@ typedef struct {
7076

7177
int64_t userdata;
7278
char local[IOS_INLSIZE];
73-
} ios_t;
79+
} ios_t);
80+
81+
#undef ON_P64
7482

7583
extern void (*ios_set_io_wait_func)(int);
7684
/* low-level interface functions */

0 commit comments

Comments
 (0)