compat: fix crash on MSVC build
Error message: stack around the variable dataout_read_index corruppted Cause: MSVC stdatomic stack and struct corruption Historically, the custom compatibility header for MSVC defined stdatomic helper functions that were not type-generic. Specifically: - atomic_compare_exchange_weak was hardcoded to a 64-bit operation using InterlockedCompareExchange64 on intptr_t* expected values. When called with a 32-bit atomic_ulong (e.g. dataout_fifo_queue_read_index), this performed a 64-bit write starting at a 32-bit address, causing stack and adjacent structure corruption on 64-bit systems. - atomic_load, atomic_store, atomic_fetch_add, and atomic_fetch_sub were hardcoded to 32-bit LONG operations, causing silent data truncation when used on 64-bit atomic_uint_fast64_t variables. Fix these issues by wrapping all interlocked helper functions with type-generic macro dispatches using compile-time sizeof(*(p_a)) branching, safely routing to either 32-bit or 64-bit versions of the Windows Interlocked APIs.
This commit is contained in:
+81
-12
@@ -39,26 +39,95 @@ typedef enum {
|
||||
} msvc_atomic_memory_order;
|
||||
|
||||
#define atomic_init(p_a, v) atomic_store(p_a, v)
|
||||
#define atomic_store(p_a, v) InterlockedExchange((LONG*)p_a, v)
|
||||
#define atomic_load(p_a) InterlockedCompareExchange((LONG*)p_a, 0, 0)
|
||||
|
||||
static inline ULONG atomic_load_32(volatile ULONG *p_a)
|
||||
{
|
||||
return (ULONG)InterlockedCompareExchange((LONG volatile *)p_a, 0, 0);
|
||||
}
|
||||
|
||||
static inline ULONG64 atomic_load_64(volatile ULONG64 *p_a)
|
||||
{
|
||||
return (ULONG64)InterlockedCompareExchange64((LONG64 volatile *)p_a, 0, 0);
|
||||
}
|
||||
|
||||
#define atomic_load(p_a) \
|
||||
(sizeof(*(p_a)) == 8 ? \
|
||||
(uint64_t)atomic_load_64((volatile ULONG64 *)(p_a)) : \
|
||||
(uint64_t)atomic_load_32((volatile ULONG *)(p_a)))
|
||||
|
||||
static inline void atomic_store_32(volatile ULONG *p_a, ULONG v)
|
||||
{
|
||||
InterlockedExchange((LONG volatile *)p_a, (LONG)v);
|
||||
}
|
||||
|
||||
static inline void atomic_store_64(volatile ULONG64 *p_a, ULONG64 v)
|
||||
{
|
||||
InterlockedExchange64((LONG64 volatile *)p_a, (LONG64)v);
|
||||
}
|
||||
|
||||
#define atomic_store(p_a, v) \
|
||||
do { \
|
||||
if (sizeof(*(p_a)) == 8) \
|
||||
atomic_store_64((volatile ULONG64 *)(p_a), (ULONG64)(v)); \
|
||||
else \
|
||||
atomic_store_32((volatile ULONG *)(p_a), (ULONG)(v)); \
|
||||
} while (0)
|
||||
|
||||
#define atomic_load_explicit(p_a, mo) atomic_load(p_a)
|
||||
#define atomic_store_explicit(p_a, v, mo) atomic_store(p_a, v)
|
||||
|
||||
/*
|
||||
* TODO use a special call to increment/decrement
|
||||
* using InterlockedIncrement/InterlockedDecrement
|
||||
*/
|
||||
#define atomic_fetch_add(p_a, inc) InterlockedExchangeAdd((LPLONG)p_a, inc)
|
||||
#define atomic_fetch_sub(p_a, dec) InterlockedExchangeAdd((LPLONG)p_a, -(int)(dec))
|
||||
static inline ULONG atomic_fetch_add_32(volatile ULONG *p_a, ULONG inc)
|
||||
{
|
||||
return (ULONG)InterlockedExchangeAdd((LONG volatile *)p_a, (LONG)inc);
|
||||
}
|
||||
|
||||
static inline ULONG64 atomic_fetch_add_64(volatile ULONG64 *p_a, ULONG64 inc)
|
||||
{
|
||||
return (ULONG64)InterlockedExchangeAdd64((LONG64 volatile *)p_a, (LONG64)inc);
|
||||
}
|
||||
|
||||
#define atomic_fetch_add(p_a, inc) \
|
||||
(sizeof(*(p_a)) == 8 ? \
|
||||
(uint64_t)atomic_fetch_add_64((volatile ULONG64 *)(p_a), (ULONG64)(inc)) : \
|
||||
(uint64_t)atomic_fetch_add_32((volatile ULONG *)(p_a), (ULONG)(inc)))
|
||||
|
||||
static inline ULONG atomic_fetch_sub_32(volatile ULONG *p_a, ULONG dec)
|
||||
{
|
||||
return (ULONG)InterlockedExchangeAdd((LONG volatile *)p_a, -(LONG)dec);
|
||||
}
|
||||
|
||||
static inline ULONG64 atomic_fetch_sub_64(volatile ULONG64 *p_a, ULONG64 dec)
|
||||
{
|
||||
return (ULONG64)InterlockedExchangeAdd64((LONG64 volatile *)p_a, -(LONG64)dec);
|
||||
}
|
||||
|
||||
#define atomic_fetch_sub(p_a, dec) \
|
||||
(sizeof(*(p_a)) == 8 ? \
|
||||
(uint64_t)atomic_fetch_sub_64((volatile ULONG64 *)(p_a), (ULONG64)(dec)) : \
|
||||
(uint64_t)atomic_fetch_sub_32((volatile ULONG *)(p_a), (ULONG)(dec)))
|
||||
|
||||
#define atomic_fetch_add_explicit(p_a, inc, mo) atomic_fetch_add(p_a, inc)
|
||||
#define atomic_fetch_sub_explicit(p_a, inc, mo) atomic_fetch_sub(p_a, inc)
|
||||
static inline int atomic_compare_exchange_weak(intptr_t *obj, intptr_t *expected, intptr_t desired)
|
||||
|
||||
static inline int atomic_compare_exchange_weak_32(volatile ULONG *obj, ULONG *expected, ULONG desired)
|
||||
{
|
||||
intptr_t old = *expected;
|
||||
*expected = (intptr_t)InterlockedCompareExchange64((PVOID *)obj,(PVOID) desired, (PVOID)*expected);
|
||||
return old == *expected;
|
||||
ULONG old = *expected;
|
||||
*expected = (ULONG)InterlockedCompareExchange((LONG volatile *)obj, (LONG)desired, (LONG)old);
|
||||
return old == *expected;
|
||||
}
|
||||
|
||||
static inline int atomic_compare_exchange_weak_64(volatile ULONG64 *obj, ULONG64 *expected, ULONG64 desired)
|
||||
{
|
||||
ULONG64 old = *expected;
|
||||
*expected = (ULONG64)InterlockedCompareExchange64((LONG64 volatile *)obj, (LONG64)desired, (LONG64)old);
|
||||
return old == *expected;
|
||||
}
|
||||
|
||||
#define atomic_compare_exchange_weak(obj, expected, desired) \
|
||||
(sizeof(*(obj)) == 8 ? \
|
||||
atomic_compare_exchange_weak_64((volatile ULONG64 *)(obj), (ULONG64 *)(expected), (ULONG64)(desired)) : \
|
||||
atomic_compare_exchange_weak_32((volatile ULONG *)(obj), (ULONG *)(expected), (ULONG)(desired)))
|
||||
|
||||
#endif /* ! stdatomic.h */
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
Reference in New Issue
Block a user