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:
RossWang
2026-05-23 14:14:42 +08:00
parent 88467c0e4e
commit 6abc10e1c1
+81 -12
View File
@@ -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)