Skip to content

Commit f915bc2

Browse files
committed
Add Arm64 TSAN support and fix JIT cache coherency
This commit adds ThreadSanitizer (TSAN) support for ARM64/Apple Silicon and fixes critical JIT instruction cache coherency issues. ARM64 TSAN Support: - Extended TSAN-compatible memory allocation to ARM64 architecture - Main memory allocated at fixed address 0x150000000000 (21TB) - JIT buffer allocated at 0x151000000000 with MAP_JIT for Apple Silicon - Both allocations avoid TSAN shadow memory and enable race detection - Note: Requires ASLR disabled on macOS (SIP restrictions may apply) JIT Cache Coherency Fixes: 1. Fixed pthread_jit_write_protect_np() ordering in update_branch_imm 2. Added sys_icache_invalidate() in update_branch_imm 3. Added cache invalidation in resolve_jumps() for x86_64
1 parent 3bdcec5 commit f915bc2

File tree

2 files changed

+55
-11
lines changed

2 files changed

+55
-11
lines changed

src/io.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,32 @@ memory_t *memory_new(uint32_t size)
2727
return NULL;
2828
assert(mem);
2929
#if HAVE_MMAP
30-
#if defined(TSAN_ENABLED) && defined(__x86_64__)
30+
#if defined(TSAN_ENABLED)
3131
/* ThreadSanitizer compatibility: Use MAP_FIXED to allocate at a specific
32-
* address within TSAN's app range (0x7cf000000000 - 0x7ffffffff000).
32+
* address to avoid conflicts with TSAN's shadow memory.
33+
*/
34+
#if defined(__x86_64__)
35+
/* x86_64: Allocate within TSAN's range (0x7cf000000000 - 0x7ffffffff000).
3336
*
3437
* Fixed address: 0x7d0000000000
3538
* Size: up to 4GB (0x100000000)
3639
* End: 0x7d0100000000 (well within app range)
37-
*
38-
* This guarantees the allocation won't land in TSAN's shadow memory,
39-
* preventing "unexpected memory mapping" errors.
4040
*/
4141
void *fixed_addr = (void *) 0x7d0000000000UL;
42+
#elif defined(__aarch64__)
43+
/* ARM64 (macOS/Apple Silicon): Use higher address range.
44+
*
45+
* Fixed address: 0x150000000000 (21TB)
46+
* Size: up to 4GB (0x100000000)
47+
* End: 0x150100000000
48+
*
49+
* This avoids TSAN's shadow memory and typical process allocations.
50+
* Requires ASLR disabled via: setarch $(uname -m) -R
51+
*/
52+
void *fixed_addr = (void *) 0x150000000000UL;
53+
#else
54+
#error "TSAN is only supported on x86_64 and aarch64"
55+
#endif
4256
data_memory_base = mmap(fixed_addr, size, PROT_READ | PROT_WRITE,
4357
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
4458
if (data_memory_base == MAP_FAILED) {

src/jit.c

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,10 @@ static void update_branch_imm(struct jit_state *state,
593593
assert((imm & 3) == 0);
594594
uint32_t insn;
595595
imm >>= 2;
596+
#if defined(__APPLE__) && defined(__aarch64__)
597+
/* Must be in write mode to read/write MAP_JIT memory on Apple ARM64 */
598+
pthread_jit_write_protect_np(false);
599+
#endif
596600
memcpy(&insn, state->buf + offset, sizeof(uint32_t));
597601
if ((insn & 0xfe000000U) == 0x54000000U /* Conditional branch immediate. */
598602
|| (insn & 0x7e000000U) ==
@@ -607,10 +611,8 @@ static void update_branch_imm(struct jit_state *state,
607611
assert(false);
608612
insn = BAD_OPCODE;
609613
}
610-
#if defined(__APPLE__) && defined(__aarch64__)
611-
pthread_jit_write_protect_np(false);
612-
#endif
613614
memcpy(state->buf + offset, &insn, sizeof(uint32_t));
615+
sys_icache_invalidate(state->buf + offset, sizeof(uint32_t));
614616
#if defined(__APPLE__) && defined(__aarch64__)
615617
pthread_jit_write_protect_np(true);
616618
#endif
@@ -2229,6 +2231,7 @@ static void resolve_jumps(struct jit_state *state)
22292231

22302232
uint8_t *offset_ptr = &state->buf[jump.offset_loc];
22312233
memcpy(offset_ptr, &rel, sizeof(uint32_t));
2234+
sys_icache_invalidate(offset_ptr, sizeof(uint32_t));
22322235
#elif defined(__aarch64__)
22332236
int32_t rel = target_loc - jump.offset_loc;
22342237
update_branch_imm(state, jump.offset_loc, rel);
@@ -2336,10 +2339,12 @@ struct jit_state *jit_state_init(size_t size)
23362339

23372340
state->offset = 0;
23382341
state->size = size;
2339-
#if defined(TSAN_ENABLED) && defined(__x86_64__)
2342+
#if defined(TSAN_ENABLED)
23402343
/* ThreadSanitizer compatibility: Allocate JIT code buffer at a fixed
23412344
* address above the main memory region to avoid conflicts.
2342-
*
2345+
*/
2346+
#if defined(__x86_64__)
2347+
/* x86_64 memory layout:
23432348
* Main memory: 0x7d0000000000 - 0x7d0100000000 (4GB for FULL4G)
23442349
* JIT buffer: 0x7d1000000000 + size
23452350
*
@@ -2348,7 +2353,32 @@ struct jit_state *jit_state_init(size_t size)
23482353
*/
23492354
void *jit_addr = (void *) 0x7d1000000000UL;
23502355
state->buf = mmap(jit_addr, size, PROT_READ | PROT_WRITE | PROT_EXEC,
2351-
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
2356+
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED
2357+
#if defined(__APPLE__)
2358+
| MAP_JIT
2359+
#endif
2360+
,
2361+
-1, 0);
2362+
#elif defined(__aarch64__)
2363+
/* ARM64 memory layout (macOS/Apple Silicon):
2364+
* Main memory: 0x150000000000 - 0x150100000000 (4GB for FULL4G)
2365+
* JIT buffer: 0x151000000000 + size
2366+
*
2367+
* Apple Silicon requires MAP_JIT for executable memory. The fixed
2368+
* address is chosen to avoid TSAN's shadow memory and typical process
2369+
* allocations. Requires ASLR disabled via: setarch $(uname -m) -R
2370+
*/
2371+
void *jit_addr = (void *) 0x151000000000UL;
2372+
state->buf = mmap(jit_addr, size, PROT_READ | PROT_WRITE | PROT_EXEC,
2373+
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED
2374+
#if defined(__APPLE__)
2375+
| MAP_JIT
2376+
#endif
2377+
,
2378+
-1, 0);
2379+
#else
2380+
#error "TSAN is only supported on x86_64 and aarch64"
2381+
#endif
23522382
if (state->buf == MAP_FAILED) {
23532383
free(state);
23542384
return NULL;

0 commit comments

Comments
 (0)