8000 gh-117657: TSAN Fix races in `PyMember_Get` and `PyMember_Set`, for C extensions by dpdani · Pull Request #123211 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-117657: TSAN Fix races in PyMember_Get and PyMember_Set, for C extensions #123211

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d63eccb
gh-117657: TSAN Fix races in `PyMember_Get` and `PyMember_Set`, for C…
dpdani Aug 21, 2024
c2d3d41
exercise race in T_CHAR as well
dpdani Aug 21, 2024
f6ba4a3
signed char races
dpdani Aug 22, 2024
d9614b7
unsigned char race
dpdani Aug 22, 2024
1659849
unsigned char race 👀
dpdani Aug 22, 2024
4cfa619
unsigned char race 👀
dpdani Aug 22, 2024
107a9f5
signed short race
dpdani Aug 22, 2024
e20b9d1
unsigned short race
dpdani Aug 22, 2024
86a0945
signed int race
dpdani Aug 22, 2024
1a07031
who uses MSC anyways?
dpdani Aug 22, 2024
16f61d8
unsigned int races
dpdani Aug 22, 2024
cf25726
👀
dpdani Aug 22, 2024
d41132c
signed long race
dpdani Aug 22, 2024
2212605
unsi 8000 gned long race
dpdani Aug 22, 2024
74616d6
ssizet race
dpdani Aug 22, 2024
23d10c6
float race
dpdani Aug 22, 2024
ae37a8e
double race
dpdani Aug 22, 2024
bce02d0
T_CHAR
dpdani Aug 22, 2024
afe2504
signed long long race
dpdani Aug 22, 2024
3dfaab8
unsigned long long race
dpdani Aug 22, 2024
50a7bb6
fix return type
dpdani Aug 22, 2024
416e0bb
arm64 does not have 128-bit integers, I suppose
dpdani Aug 22, 2024
4bd6927
at this point I'm just making guesses
dpdani Aug 22, 2024
a4c094b
scope
dpdani Aug 29, 2024
267f995
must 0-initialize
dpdani Aug 29, 2024
c006e1d
FT_ATOMIC_STORE_CHAR_RELEASE -> FT_ATOMIC_STORE_CHAR_RELAXED
dpdani Aug 29, 2024
488dea5
remaining release -> relaxed
dpdani Aug 29, 2024
b3b07d5
default build
dpdani Aug 29, 2024
761257e
Apply suggestions from code review
dpdani Sep 22, 2024
d045747
missing load
dpdani Sep 22, 2024
c1b4c35
fixes
dpdani Nov 2, 2024
6c5cec5
Merge branch 'main' into gh-117657-tsan-pymember-c-ext
colesbury Dec 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
remaining release -> relaxed
  • Loading branch information
dpdani committed Aug 29, 2024
commit 488dea52797332afd539797cbce8d93c17d3bd08
47 changes: 20 additions & 27 deletions Include/cpython/pyatomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,56 +482,49 @@ _Py_atomic_store_ullong_relaxed(unsigned long long *obj,
static inline void
_Py_atomic_store_char_relaxed(char *obj, char value);


// --- _Py_atomic_load_ptr_acquire / _Py_atomic_store_ptr_release ------------

// Loads `*obj` (acquire operation)
static inline void *
_Py_atomic_load_ptr_acquire(const void *obj);

static inline uintptr_t
_Py_atomic_load_uintptr_acquire(const uintptr_t *obj);

// Stores `*obj = value` (release operation)
static inline void
_Py_atomic_store_ptr_release(void *obj, void *value);
_Py_atomic_store_uchar_relaxed(unsigned char *obj, unsigned char value);

static inline void
_Py_atomic_store_uintptr_release(uintptr_t *obj, uintptr_t value);
_Py_atomic_store_short_relaxed(short *obj, short value);

static inline void
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value);
_Py_atomic_store_ushort_relaxed(unsigned short *obj, unsigned short value);

static inline void
_Py_atomic_store_int_release(int *obj, int value);
_Py_atomic_store_long_relaxed(long *obj, long value);

static inline void
_Py_atomic_store_uchar_release(unsigned char *obj, unsigned char value);
_Py_atomic_store_float_relaxed(float *obj, float value);

static inline void
_Py_atomic_store_short_release(short *obj, short value);
_Py_atomic_store_double_relaxed(double *obj, double value);

static inline void
_Py_atomic_store_ushort_release(unsigned short *obj, unsigned short value);
_Py_atomic_store_llong_relaxed(long long *obj, long long value);

static inline void
_Py_atomic_store_uint_release(unsigned int *obj, unsigned int value);

static inline void
_Py_atomic_store_long_release(long *obj, long value);
// --- _Py_atomic_load_ptr_acquire / _Py_atomic_store_ptr_release ------------

// Loads `*obj` (acquire operation)
static inline void *
_Py_atomic_load_ptr_acquire(const void *obj);

static inline uintptr_t
_Py_atomic_load_uintptr_acquire(const uintptr_t *obj);

// Stores `*obj = value` (release operation)
static inline void
_Py_atomic_store_float_release(float *obj, float value);
_Py_atomic_store_ptr_release(void *obj, void *value);

static inline void
_Py_atomic_store_double_release(double *obj, double value);
_Py_atomic_store_uintptr_release(uintptr_t *obj, uintptr_t value);

static inline void
_Py_atomic_store_llong_release(long long *obj, long long value);
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value);

static inline void
_Py_atomic_store_ullong_release(unsigned long long *obj,
unsigned long long value);
_Py_atomic_store_int_release(int *obj, int value);

static inline int
_Py_atomic_load_int_acquire(const int *obj);
Expand Down
63 changes: 27 additions & 36 deletions Include/cpython/pyatomic_gcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -521,64 +521,55 @@ static inline void
_Py_atomic_store_char_relaxed(char *obj, char value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }


// --- _Py_atomic_load_ptr_acquire / _Py_atomic_store_ptr_release ------------

static inline void *
_Py_atomic_load_ptr_acquire(const void *obj)
{ return (void *)__atomic_load_n((void * const *)obj, __ATOMIC_ACQUIRE); }

static inline uintptr_t
_Py_atomic_load_uintptr_acquire(const uintptr_t *obj)
{ return (uintptr_t)__atomic_load_n(obj, __ATOMIC_ACQUIRE); }

static inline void
_Py_atomic_store_ptr_release(void *obj, void *value)
{ __atomic_store_n((void **)obj, value, __ATOMIC_RELEASE); }
_Py_atomic_store_uchar_relaxed(unsigned char *obj, unsigned char value)
{ __atomic_store_n(obj, value, __ATOMIC_RELAXED); }

static inline void
_Py_atomic_store_uintptr_release(uintptr_t *obj, uintptr_t value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
_Py_atomic_store_short_relaxed(short *obj, short value)
{ __atomic_store_n(obj, value, __ATOMIC_RELAXED); }

static inline void
_Py_atomic_store_int_release(int *obj, int value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
_Py_atomic_store_ushort_relaxed(unsigned short *obj, unsigned short value)
{ __atomic_store_n(obj, value, __ATOMIC_RELAXED); }

static inline void
_Py_atomic_store_uchar_release(unsigned char *obj, unsigned char value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
_Py_atomic_store_long_relaxed(long *obj, long value)
{ __atomic_store_n(obj, value, __ATOMIC_RELAXED); }

static inline void
_Py_atomic_store_short_release(short *obj, short value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
_Py_atomic_store_float_relaxed(float *obj, float value)
{ __atomic_store(obj, &value, __ATOMIC_RELAXED); }

static inline void
_Py_atomic_store_ushort_release(unsigned short *obj, unsigned short value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
_Py_atomic_store_double_relaxed(double *obj, double value)
{ __atomic_store(obj, &value, __ATOMIC_RELAXED); }

static inline void
_Py_atomic_store_uint_release(unsigned int *obj, unsigned int value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
_Py_atomic_store_llong_relaxed(long long *obj, long long value)
{ __atomic_store_n(obj, value, __ATOMIC_RELAXED); }

static inline void
_Py_atomic_store_long_release(long *obj, long value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }

static inline void
_Py_atomic_store_float_release(float *obj, float value)
{ __atomic_store(obj, &value, __ATOMIC_RELEASE); }
// --- _Py_atomic_load_ptr_acquire / _Py_atomic_store_ptr_release ------------

static inline void *
_Py_atomic_load_ptr_acquire(const void *obj)
{ return (void *)__atomic_load_n((void * const *)obj, __ATOMIC_ACQUIRE); }

static inline uintptr_t
_Py_atomic_load_uintptr_acquire(const uintptr_t *obj)
{ return (uintptr_t)__atomic_load_n(obj, __ATOMIC_ACQUIRE); }

static inline void
_Py_atomic_store_double_release(double *obj, double value)
{ __atomic_store(obj, &value, __ATOMIC_RELEASE); }
_Py_atomic_store_ptr_release(void *obj, void *value)
{ __atomic_store_n((void **)obj, value, __ATOMIC_RELEASE); }

static inline void
_Py_atomic_store_llong_release(long long *obj, long long value)
_Py_atomic_store_uintptr_release(uintptr_t *obj, uintptr_t value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }

static inline void
_Py_atomic_store_ullong_release(unsigned long long *obj,
unsigned long long value)
_Py_atomic_store_int_release(int *obj, int value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }

static inline void
Expand Down
153 changes: 42 additions & 111 deletions Include/cpython/pyatomic_msc.h
Original file line number Diff line number Diff line change
Expand Up @@ -953,185 +953,116 @@ _Py_atomic_store_char_relaxed(char *obj, char value)
*(volatile char *)obj = value;
}


// --- _Py_atomic_load_ptr_acquire / _Py_atomic_store_ptr_release ------------

static inline void *
_Py_atomic_load_ptr_acquire(const void *obj)
{
#if defined(_M_X64) || defined(_M_IX86)
return *(void * volatile *)obj;
#elif defined(_M_ARM64)
return (void *)__ldar64((unsigned __int64 volatile *)obj);
#else
# error "no implementation of _Py_atomic_load_ptr_acquire"
#endif
}

static inline uintptr_t
_Py_atomic_load_uintptr_acquire(const uintptr_t *obj)
static inline void
_Py_atomic_store_uchar_relaxed(unsigned char *obj, unsigned char value)
{
#if defined(_M_X64) || defined(_M_IX86)
return *(uintptr_t volatile *)obj;
#elif defined(_M_ARM64)
return (uintptr_t)__ldar64((unsigned __int64 volatile *)obj);
#else
# error "no implementation of _Py_atomic_load_uintptr_acquire"
#endif
*(volatile unsigned char*)obj = value;
}

static inline void
_Py_atomic_store_ptr_release(void *obj, void *value)
_Py_atomic_store_short_relaxed(short *obj, short value)
{
#if defined(_M_X64) || defined(_M_IX86)
*(void * volatile *)obj = value;
#elif defined(_M_ARM64)
__stlr64((unsigned __int64 volatile *)obj, (uintptr_t)value);
#else
# error "no implementation of _Py_atomic_store_ptr_release"
#endif
*(volatile short*)obj = value;
}

static inline void
_Py_atomic_store_uintptr_release(uintptr_t *obj, uintptr_t value)
_Py_atomic_store_ushort_relaxed(unsigned short *obj, unsigned short value)
{
#if defined(_M_X64) || defined(_M_IX86)
*(uintptr_t volatile *)obj = value;
#elif defined(_M_ARM64)
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int64);
__stlr64((unsigned __int64 volatile *)obj, (unsigned __int64)value);
#else
# error "no implementation of _Py_atomic_store_uintptr_release"
#endif
*(volatile unsigned short*)obj = value;
}

static inline void
_Py_atomic_store_int_release(int *obj, int value)
_Py_atomic_store_uint_release(unsigned int *obj, unsigned int value)
{
#if defined(_M_X64) || defined(_M_IX86)
*(int volatile *)obj = value;
#elif defined(_M_ARM64)
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int32);
__stlr32((unsigned __int32 volatile *)obj, (unsigned __int32)value);
#else
# error "no implementation of _Py_atomic_store_int_release"
#endif
*(volatile unsigned int*)obj = value;
}

static inline void
_Py_atomic_store_uchar_release(unsigned char *obj, unsigned char value)
_Py_atomic_store_long_relaxed(long *obj, long value)
{
#if defined(_M_X64) || defined(_M_IX86)
*(unsigned char volatile *)obj = value;
#elif defined(_M_ARM64)
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int8);
__stlr8((unsigned __int8 volatile *)obj, (unsigned __int8)value);
#else
# error "no implementation of _Py_atomic_store_uchar_release"
#endif
*(volatile long *)obj = value;
}

static inline void
_Py_atomic_store_short_release(short *obj, short value)
_Py_atomic_store_float_relaxed(float *obj, float value)
{
#if defined(_M_X64) || defined(_M_IX86)
*(short volatile *)obj = value;
#elif defined(_M_ARM64)
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int16);
__stlr16((unsigned __int16 volatile *)obj, (unsigned __int16)value);
#else
# error "no implementation of _Py_atomic_store_short_release"
#endif
*(volatile float *)obj = value;
}

static inline void
_Py_atomic_store_ushort_release(unsigned short *obj, unsigned short value)
_Py_atomic_store_double_relaxed(double *obj, double value)
{
#if defined(_M_X64) || defined(_M_IX86)
*(unsigned short volatile *)obj = value;
#elif defined(_M_ARM64)
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int16);
__stlr16((unsigned __int16 volatile *)obj, (unsigned __int16)value);
#else
# error "no implementation of _Py_atomic_store_ushort_release"
#endif
*(volatile double *)obj = value;
}

static inline void
_Py_atomic_store_uint_release(unsigned int *obj, unsigned int value)
_Py_atomic_store_llong_relaxed(long long *obj, long long value)
{
#if defined(_M_X64) || defined(_M_IX86)
*(unsigned int volatile *)obj = value;
#elif defined(_M_ARM64)
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int32);
__stlr32((unsigned __int32 volatile *)obj, (unsigned __int32)value);
#else
# error "no implementation of _Py_atomic_store_uint_release"
#endif
*(volatile long long*)obj = value;
}

static inline void
_Py_atomic_store_long_release(long *obj, long value)

// --- _Py_atomic_load_ptr_acquire / _Py_atomic_store_ptr_release ------------

static inline void *
_Py_atomic_load_ptr_acquire(const void *obj)
{
#if defined(_M_X64) || defined(_M_IX86)
*(long volatile *)obj = value;
return *(void * volatile *)obj;
#elif defined(_M_ARM64)
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int32);
__stlr32((unsigned __int32 volatile *)obj, (unsigned __int32)value);
return (void *)__ldar64((unsigned __int64 volatile *)obj);
#else
# error "no implementation of _Py_atomic_store_long_release"
# error "no implementation of _Py_atomic_load_ptr_acquire"
#endif
}

static inline void
_Py_atomic_store_float_release(float *obj, float value)
static inline uintptr_t
_Py_atomic_load_uintptr_acquire(const uintptr_t *obj)
{
#if defined(_M_X64) || defined(_M_IX86)
*(float volatile *)obj = value;
return *(uintptr_t volatile *)obj;
#elif defined(_M_ARM64)
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int32);
__stlr32((unsigned __int32 volatile *)obj, (unsigned __int32)value);
return (uintptr_t)__ldar64((unsigned __int64 volatile *)obj);
#else
# error "no implementation of _Py_atomic_store_float_release"
# error "no implementation of _Py_atomic_load_uintptr_acquire"
#endif
}

static inline void
_Py_atomic_store_double_release(double *obj, double value)
_Py_atomic_store_ptr_release(void *obj, void *value)
{
#if defined(_M_X64) || defined(_M_IX86)
*(double volatile *)obj = value;
*(void * volatile *)obj = value;
#elif defined(_M_ARM64)
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int64);
__stlr64((unsigned __int64 volatile *)obj, (unsigned __int64)value);
__stlr64((unsigned __int64 volatile *)obj, (uintptr_t)value);
#else
# error "no implementation of _Py_atomic_store_double_release"
# error "no implementation of _Py_atomic_store_ptr_release"
#endif
}

static inline void
_Py_atomic_store_llong_release(long long *obj, long long value)
_Py_atomic_store_uintptr_release(uintptr_t *obj, uintptr_t value)
{
#if defined(_M_X64) || defined(_M_IX86)
*(long long volatile *)obj = value;
*(uintptr_t volatile *)obj = value;
#elif defined(_M_ARM64)
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int64);
__stlr64((unsigned __int64 volatile *)obj, (unsigned __int64)value);
#else
# error "no implementation of _Py_atomic_store_llong_release"
# error "no implementation of _Py_atomic_store_uintptr_release"
#endif
}

static inline void
_Py_atomic_store_ullong_release(unsigned long long *obj, unsigned long long value)
_Py_atomic_store_int_release(int *obj, int value)
{
#if defined(_M_X64) || defined(_M_IX86)
*(unsigned long long volatile *)obj = value;
*(int volatile *)obj = value;
#elif defined(_M_ARM64)
_Py_atomic_ASSERT_ARG_TYPE(__int64);
__stlr64((unsigned __int64 volatile *)obj, (unsigned __int64)value);
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int32);
__stlr32((unsigned __int32 volatile *)obj, (unsigned __int32)value);
#else
# error "no implementation of _Py_atomic_store_ullong_release"
# error "no implementation of _Py_atomic_store_int_release"
#endif
}

Expand Down
Loading
Loading
0