Commit 9031f3d9 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

bump c/x success order until c++17

Summary:
We currently bump it for clang+tsan because the clang implementation of tsan historically implements the historical pre-c++17 rule even post-c++17. But to enable libstdc++ assertions, we must also bump it for for some versions of libstdc++ when assertions are enabled.

The assertions are removed in libstdc++ trunk: https://github.com/gcc-mirror/gcc/commit/dba1ab212292839572fda60df00965e094a11252. They remain in libstdc++11.2.

Reviewed By: ot

Differential Revision: D31593055

fbshipit-source-id: a339306e86452c4bb6d9d821cd28038ab6f49767
parent ae1e90a3
...@@ -470,6 +470,12 @@ constexpr auto kGlibcxxVer = _GLIBCXX_RELEASE; ...@@ -470,6 +470,12 @@ constexpr auto kGlibcxxVer = _GLIBCXX_RELEASE;
constexpr auto kGlibcxxVer = 0; constexpr auto kGlibcxxVer = 0;
#endif #endif
#if __GLIBCXX__ && defined(_GLIBCXX_ASSERTIONS)
constexpr auto kGlibcxxAssertions = true;
#else
constexpr auto kGlibcxxAssertions = false;
#endif
#if _LIBCPP_VERSION #if _LIBCPP_VERSION
constexpr auto kIsLibcpp = true; constexpr auto kIsLibcpp = true;
#else #else
......
...@@ -42,18 +42,40 @@ constexpr std::memory_order atomic_compare_exchange_succ( ...@@ -42,18 +42,40 @@ constexpr std::memory_order atomic_compare_exchange_succ(
assert(fail != release); assert(fail != release);
assert(fail != acq_rel); assert(fail != acq_rel);
// Clang TSAN ignores the passed failure order and infers failure order from
// success order in atomic compare-exchange operations, which is broken for
// cases like success-release/failure-acquire, so return a success order with
// the failure order mixed in.
auto const bump = succ == release ? acq_rel : succ; auto const bump = succ == release ? acq_rel : succ;
auto const high = fail < bump ? bump : fail; auto const high = fail < bump ? bump : fail;
return !cond || fail == relaxed ? succ : high; return !cond || fail == relaxed ? succ : high;
} }
// atomic_compare_exchange_succ
//
// Return a success order with, conditionally, the failure order mixed in.
//
// Until C++17, atomic compare-exchange operations require the success order to
// be at least as strong as the failure order. C++17 drops this requirement. As
// an implication, were this rule in force, an implementation is free to ignore
// the explicit failure order and to infer one from the success order.
//
// https://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange
//
// The libstdc++ library with assertions enabled enforces this rule, including
// under C++17, but only until and not since libstdc++12.
//
// https://github.com/gcc-mirror/gcc/commit/dba1ab212292839572fda60df00965e094a11252
//
// Clang TSAN ignores the passed failure order and infers failure order from
// success order in atomic compare-exchange operations, which is broken for
// cases like success-release/failure-acquire.
//
// https://github.com/google/sanitizers/issues/970
//
// Handle all of these cases.
constexpr std::memory_order atomic_compare_exchange_succ( constexpr std::memory_order atomic_compare_exchange_succ(
std::memory_order succ, std::memory_order fail) { std::memory_order succ, std::memory_order fail) {
constexpr auto const cond = kIsSanitizeThread && kIsClang; constexpr auto const cond = false //
|| (FOLLY_CPLUSPLUS < 201702L) //
|| (kGlibcxxVer && kGlibcxxVer < 12 && kGlibcxxAssertions) //
|| (kIsSanitizeThread && kIsClang);
return atomic_compare_exchange_succ(cond, succ, fail); return atomic_compare_exchange_succ(cond, succ, fail);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment