Skip to content

Commit

Permalink
Fix various alignment violations (JuliaLang#32513)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Keno committed Jul 11, 2019
1 parent c690489 commit 24efaa4
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 143 deletions.
3 changes: 2 additions & 1 deletion src/flisp/cvalues.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ static int cvalue_##ctype##_init(fl_context_t *fl_ctx, fltype_t *type, \
else { \
return 1; \
} \
*((fl_##ctype##_t*)dest) = n; \
memcpy(jl_assume_aligned(dest, sizeof(void*)), &n, \
sizeof(fl_##ctype##_t)); \
return 0; \
}
num_init(int8, int32, T_INT8)
Expand Down
9 changes: 5 additions & 4 deletions src/flisp/flisp.c
Original file line number Diff line number Diff line change
Expand Up @@ -990,11 +990,12 @@ static uint32_t process_keys(fl_context_t *fl_ctx, value_t kwtable,
((int16_t) \
((((int16_t)a[0])<<0) | \
(((int16_t)a[1])<<8)))
#define PUT_INT32(a,i) (*(int32_t*)(a) = bswap_32((int32_t)(i)))
#define PUT_INT32(a,i) jl_store_unaligned_i32((void*)a,
(uint32_t)bswap_32((int32_t)(i)))
#else
#define GET_INT32(a) (*(int32_t*)a)
#define GET_INT16(a) (*(int16_t*)a)
#define PUT_INT32(a,i) (*(int32_t*)(a) = (int32_t)(i))
#define GET_INT32(a) (int32_t)jl_load_unaligned_i32((void*)a)
#define GET_INT16(a) (int16_t)jl_load_unaligned_i16((void*)a)
#define PUT_INT32(a,i) jl_store_unaligned_i32((void*)a, (uint32_t)(i))
#endif
#define SWAP_INT32(a) (*(int32_t*)(a) = bswap_32(*(int32_t*)(a)))
#define SWAP_INT16(a) (*(int16_t*)(a) = bswap_16(*(int16_t*)(a)))
Expand Down
7 changes: 5 additions & 2 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@
#include <setjmp.h>
#ifndef _OS_WINDOWS_
# define jl_jmp_buf sigjmp_buf
# if defined(_CPU_ARM_) || defined(_CPU_PPC_)
# if defined(_CPU_ARM_) || defined(_CPU_PPC_) || defined(_CPU_WASM_)
# define MAX_ALIGN 8
# elif defined(_CPU_AARCH64_)
// int128 is 16 bytes aligned on aarch64
# define MAX_ALIGN 16
# elif defined(_P64)
// Generically we assume MAX_ALIGN is sizeof(void*)
# define MAX_ALIGN 8
# else
# define MAX_ALIGN sizeof(void*)
# define MAX_ALIGN 4
# endif
#else
# include "win32_ucontext.h"
Expand Down
74 changes: 3 additions & 71 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@
#define sleep(x) Sleep(1000*x)
#endif

#ifdef __has_builtin
# define jl_has_builtin(x) __has_builtin(x)
#else
# define jl_has_builtin(x) 0
#endif

#if defined(__has_feature)
#if __has_feature(address_sanitizer)
#define JL_ASAN_ENABLED // Clang flavor
Expand Down Expand Up @@ -57,42 +51,6 @@
# endif
#endif

#if jl_has_builtin(__builtin_assume)
#define jl_assume(cond) (__extension__ ({ \
__typeof__(cond) cond_ = (cond); \
__builtin_assume(!!(cond_)); \
cond_; \
}))
#elif defined(_COMPILER_MICROSOFT_) && defined(__cplusplus)
template<typename T>
static inline T
jl_assume(T v)
{
__assume(!!v);
return v;
}
#elif defined(_COMPILER_INTEL_)
#define jl_assume(cond) (__extension__ ({ \
__typeof__(cond) cond_ = (cond); \
__assume(!!(cond_)); \
cond_; \
}))
#elif defined(__GNUC__)
static inline void jl_assume_(int cond)
{
if (!cond) {
__builtin_unreachable();
}
}
#define jl_assume(cond) (__extension__ ({ \
__typeof__(cond) cond_ = (cond); \
jl_assume_(!!(cond_)); \
cond_; \
}))
#else
#define jl_assume(cond) (cond)
#endif

#if defined(__GLIBC__) && defined(JULIA_HAS_IFUNC_SUPPORT)
// Make sure both the compiler and the glibc supports it.
// Only enable this on known working glibc versions.
Expand Down Expand Up @@ -179,7 +137,7 @@ void gc_sweep_sysimg(void);
static const int jl_gc_sizeclasses[] = {
#ifdef _P64
8,
#elif defined(_CPU_ARM_) || defined(_CPU_PPC_)
#elif MAX_ALIGN == 8
// ARM and PowerPC have max alignment of 8,
// make sure allocation of size 8 has that alignment.
4, 8,
Expand Down Expand Up @@ -218,7 +176,7 @@ STATIC_INLINE int jl_gc_alignment(size_t sz)
#ifdef _P64
(void)sz;
return 16;
#elif defined(_CPU_ARM_) || defined(_CPU_PPC_)
#elif MAX_ALIGN == 8
return sz <= 4 ? 8 : 16;
#else
// szclass 8
Expand Down Expand Up @@ -246,7 +204,7 @@ STATIC_INLINE uint8_t JL_CONST_FUNC jl_gc_szclass(unsigned sz)
if (sz <= 8)
return 0;
const int N = 0;
#elif defined(_CPU_ARM_) || defined(_CPU_PPC_)
#elif MAX_ALIGN == 8
if (sz <= 8)
return (sz >= 4 ? 1 : 0);
const int N = 1;
Expand Down Expand Up @@ -1061,32 +1019,6 @@ void jl_register_fptrs(uint64_t sysimage_base, const struct _jl_sysimg_fptrs_t *

extern arraylist_t partial_inst;

#if jl_has_builtin(__builtin_assume_aligned) || defined(_COMPILER_GCC_)
#define jl_assume_aligned(ptr, align) __builtin_assume_aligned(ptr, align)
#elif defined(_COMPILER_INTEL_)
#define jl_assume_aligned(ptr, align) (__extension__ ({ \
__typeof__(ptr) ptr_ = (ptr); \
__assume_aligned(ptr_, align); \
ptr_; \
}))
#elif defined(__GNUC__)
#define jl_assume_aligned(ptr, align) (__extension__ ({ \
__typeof__(ptr) ptr_ = (ptr); \
jl_assume(((uintptr_t)ptr) % (align) == 0); \
ptr_; \
}))
#elif defined(__cplusplus)
template<typename T>
static inline T
jl_assume_aligned(T ptr, unsigned align)
{
(void)jl_assume(((uintptr_t)ptr) % align == 0);
return ptr;
}
#else
#define jl_assume_aligned(ptr, align) (ptr)
#endif

#if jl_has_builtin(__builtin_unreachable) || defined(_COMPILER_GCC_) || defined(_COMPILER_INTEL_)
# define jl_unreachable() __builtin_unreachable()
#else
Expand Down
2 changes: 1 addition & 1 deletion src/julia_threads.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ typedef struct {
// variables for allocating objects from pools
#ifdef _P64
# define JL_GC_N_POOLS 41
#elif defined(_CPU_ARM_) || defined(_CPU_PPC_)
#elif MAX_ALIGN == 8
# define JL_GC_N_POOLS 42
#else
# define JL_GC_N_POOLS 43
Expand Down
2 changes: 1 addition & 1 deletion src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ static void jl_write_gv_ints(jl_serializer_state *s)

static inline uint32_t load_uint32(uintptr_t *base)
{
uint32_t v = **(uint32_t**)base;
uint32_t v = jl_load_unaligned_i32((void*)*base);
*base += 4;
return v;
}
Expand Down
93 changes: 92 additions & 1 deletion src/support/dtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,74 @@
# define JL_ATTRIBUTE_ALIGN_PTRSIZE(x)
#endif

#ifdef __has_builtin
# define jl_has_builtin(x) __has_builtin(x)
#else
# define jl_has_builtin(x) 0
#endif

#if jl_has_builtin(__builtin_assume)
#define jl_assume(cond) (__extension__ ({ \
__typeof__(cond) cond_ = (cond); \
__builtin_assume(!!(cond_)); \
cond_; \
}))
#elif defined(_COMPILER_MICROSOFT_) && defined(__cplusplus)
template<typename T>
static inline T
jl_assume(T v)
{
__assume(!!v);
return v;
}
#elif defined(_COMPILER_INTEL_)
#define jl_assume(cond) (__extension__ ({ \
__typeof__(cond) cond_ = (cond); \
__assume(!!(cond_)); \
cond_; \
}))
#elif defined(__GNUC__)
static inline void jl_assume_(int cond)
{
if (!cond) {
__builtin_unreachable();
}
}
#define jl_assume(cond) (__extension__ ({ \
__typeof__(cond) cond_ = (cond); \
jl_assume_(!!(cond_)); \
cond_; \
}))
#else
#define jl_assume(cond) (cond)
#endif

#if jl_has_builtin(__builtin_assume_aligned) || defined(_COMPILER_GCC_)
#define jl_assume_aligned(ptr, align) __builtin_assume_aligned(ptr, align)
#elif defined(_COMPILER_INTEL_)
#define jl_assume_aligned(ptr, align) (__extension__ ({ \
__typeof__(ptr) ptr_ = (ptr); \
__assume_aligned(ptr_, align); \
ptr_; \
}))
#elif defined(__GNUC__)
#define jl_assume_aligned(ptr, align) (__extension__ ({ \
__typeof__(ptr) ptr_ = (ptr); \
jl_assume(((uintptr_t)ptr) % (align) == 0); \
ptr_; \
}))
#elif defined(__cplusplus)
template<typename T>
static inline T
jl_assume_aligned(T ptr, unsigned align)
{
(void)jl_assume(((uintptr_t)ptr) % align == 0);
return ptr;
}
#else
#define jl_assume_aligned(ptr, align) (ptr)
#endif

typedef int bool_t;
typedef unsigned char byte_t; /* 1 byte */

Expand Down Expand Up @@ -221,12 +289,35 @@ typedef enum { T_INT8, T_UINT8, T_INT16, T_UINT16, T_INT32, T_UINT32,
#define JL_UNUSED
#endif

STATIC_INLINE double jl_load_unaligned_f64(const void *ptr) JL_NOTSAFEPOINT
{
double val;
memcpy(&val, ptr, sizeof(double));
return val;
}

STATIC_INLINE uint64_t jl_load_unaligned_i64(const void *ptr) JL_NOTSAFEPOINT
{
uint64_t val;
memcpy(&val, ptr, 8);
memcpy(&val, ptr, sizeof(uint64_t));
return val;
}

STATIC_INLINE double jl_load_ptraligned_f64(const void *ptr) JL_NOTSAFEPOINT
{
double val;
memcpy(&val, jl_assume_aligned(ptr, sizeof(void*)), sizeof(double));
return val;
}

STATIC_INLINE uint64_t jl_load_ptraligned_i64(const void *ptr) JL_NOTSAFEPOINT
{
uint64_t val;
memcpy(&val, jl_assume_aligned(ptr, sizeof(void*)), sizeof(uint64_t));
return val;
}


STATIC_INLINE uint32_t jl_load_unaligned_i32(const void *ptr) JL_NOTSAFEPOINT
{
uint32_t val;
Expand Down
18 changes: 13 additions & 5 deletions src/support/ios.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,23 @@ typedef enum { bst_none, bst_rd, bst_wr } bufstate_t;
#define IOS_INLSIZE 54
#define IOS_BUFSIZE 131072

typedef struct {
#ifdef _P64
#define ON_P64(x) x
#else
#define ON_P64(x)
#endif

// We allow ios_t as a cvalue in flisp, which only guarantees pointer
// alignment. Make sure the compiler knows.
JL_ATTRIBUTE_ALIGN_PTRSIZE(typedef struct {
// the state only indicates where the underlying file position is relative
// to the buffer. reading: at the end. writing: at the beginning.
// in general, you can do any operation in any state.
char *buf; // start of buffer

int errcode;

#ifdef _P64
int _pad_bm; // put bm at same offset as type field of uv_stream_s
#endif
ON_P64(int _pad_bm;) // put bm at same offset as type field of uv_stream_s
bufmode_t bm; //
bufstate_t state;

Expand Down Expand Up @@ -70,7 +76,9 @@ typedef struct {

int64_t userdata;
char local[IOS_INLSIZE];
} ios_t;
} ios_t);

#undef ON_P64

extern void (*ios_set_io_wait_func)(int);
/* low-level interface functions */
Expand Down
Loading

0 comments on commit 24efaa4

Please sign in to comment.