Branch
Hash :
9d004544
Author :
Date :
2025-09-16T00:16:30
Fix invalid reinterpret_cast (#5558) * Fix invalid reinterpret_cast reinterpret_cast from non-atomic object to atomic object is not valid. https://eel.is/c++draft/atomics.types.generic#general-3 >[Note 2: The representation of an atomic specialization >need not have the same size and alignment requirement as >its corresponding argument type. — end note] https://eel.is/c++draft/basic.compound#5 >5 Two objects a and b are pointer-interconvertible if >(5.1) they are the same object, or >(5.2) one is a union object and the other is a non-static >data member of that object ([class.union]), or >(5.3) one is a standard-layout class object and the other >is the first non-static data member of that object or any >base class subobject of that object ([class.mem]), or >(5.4) there exists an object c such that a and c are >pointer-interconvertible, and c and b are pointer-interconvertible. >If two objects are pointer-interconvertible, then they have >the same address, and it is possible to obtain a pointer >to one from a pointer to the other via a reinterpret_cast >([expr.reinterpret.cast]). objects of types `int` and `std::atomic<int>` are not pointer-interconvertible (an object of type `int` is not first non-static data member of `std::atomic<int>`) https://eel.is/c++draft/basic.lval#11 >11 An object of dynamic type T-obj is type-accessible through >a glvalue of type T-ref if T-ref is similar ([conv.qual]) to: >(11.1) T-obj, >(11.2) a type that is the signed or unsigned type corresponding >to T-obj, or >(11.3) a char, unsigned char, or std::byte type. >If a program attempts to access ([defns.access]) the stored >value of an object through a glvalue through which it is not >type-accessible, the behavior is undefined The original code resulted in undefined behavior. * revert code formatting * fix const qualifier in type for atomic operation. * implement copy and move ctors (assignment-operators) and swap functions. * swap-functions replaced as frendly members, common header includes returned. * add HB_ prefix to defined macro. * some formatting.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
/*
* Copyright © 2007 Chris Wilson
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_ATOMIC_HH
#define HB_ATOMIC_HH
#include "hb.hh"
#include "hb-meta.hh"
/*
* Atomic integers and pointers.
*/
/* We need external help for these */
#if defined(hb_atomic_int_impl_add) \
&& defined(hb_atomic_ptr_impl_get) \
&& defined(hb_atomic_ptr_impl_cmpexch)
/* Defined externally, i.e. in config.h. */
#elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE)
/* C++11-style GCC primitives. We prefer these as they don't require linking to libstdc++ / libc++. */
#define _hb_memory_barrier() __sync_synchronize ()
#define hb_atomic_int_impl_add(AI, V) __atomic_fetch_add ((AI), (V), __ATOMIC_ACQ_REL)
#define hb_atomic_int_impl_set_relaxed(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELAXED)
#define hb_atomic_int_impl_set(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELEASE)
#define hb_atomic_int_impl_get_relaxed(AI) __atomic_load_n ((AI), __ATOMIC_RELAXED)
#define hb_atomic_int_impl_get(AI) __atomic_load_n ((AI), __ATOMIC_ACQUIRE)
#define hb_atomic_ptr_impl_set_relaxed(P, V) __atomic_store_n ((P), (V), __ATOMIC_RELAXED)
#define hb_atomic_ptr_impl_get_relaxed(P) __atomic_load_n ((P), __ATOMIC_RELAXED)
#define hb_atomic_ptr_impl_get(P) __atomic_load_n ((P), __ATOMIC_ACQUIRE)
static inline bool
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
{
const void *O = O_; // Need lvalue
return __atomic_compare_exchange_n ((void **) P, (void **) &O, (void *) N, true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
}
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
#elif !defined(HB_NO_MT)
/* C++11 atomics. */
#include <atomic>
#define HB_STL_ATOMIC_IMPL
#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire)
#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release)
#else /* defined(HB_NO_MT) */
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
#define _hb_memory_barrier() do {} while (0)
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
#endif
/* This should never be disabled, even under HB_NO_MT.
* except that MSVC gives me an internal compiler error, so disabled there.
*
* https://github.com/harfbuzz/harfbuzz/pull/4119
*/
#ifndef _hb_compiler_memory_r_barrier
#if defined(__ATOMIC_ACQUIRE) // gcc-like
static inline void _hb_compiler_memory_r_barrier () { asm volatile("": : :"memory"); }
#elif !defined(_MSC_VER)
#include <atomic>
#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
#else
static inline void _hb_compiler_memory_r_barrier () {}
#endif
#endif
#ifndef _hb_memory_r_barrier
#define _hb_memory_r_barrier() _hb_memory_barrier ()
#endif
#ifndef _hb_memory_w_barrier
#define _hb_memory_w_barrier() _hb_memory_barrier ()
#endif
#ifndef hb_atomic_int_impl_set_relaxed
#define hb_atomic_int_impl_set_relaxed(AI, V) (*(AI) = (V))
#endif
#ifndef hb_atomic_int_impl_get_relaxed
#define hb_atomic_int_impl_get_relaxed(AI) (*(AI))
#endif
#ifndef hb_atomic_ptr_impl_set_relaxed
#define hb_atomic_ptr_impl_set_relaxed(P, V) (*(P) = (V))
#endif
#ifndef hb_atomic_ptr_impl_get_relaxed
#define hb_atomic_ptr_impl_get_relaxed(P) (*(P))
#endif
#ifndef hb_atomic_int_impl_set
template <typename T>
inline void hb_atomic_int_impl_set (T *AI, T v) { _hb_memory_w_barrier (); *AI = v; }
#endif
#ifndef hb_atomic_int_impl_get
template <typename T>
inline T hb_atomic_int_impl_get (const T *AI) { T v = *AI; _hb_memory_r_barrier (); return v; }
#endif
#ifndef hb_atomic_ptr_impl_get
inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; }
#endif
#ifdef HB_STL_ATOMIC_IMPL
template <typename T>
struct hb_atomic_t
{
hb_atomic_t () = default;
constexpr hb_atomic_t (T v) : v (v) {}
constexpr hb_atomic_t (const hb_atomic_t& o) : v (o.get_relaxed ()) {}
constexpr hb_atomic_t (hb_atomic_t&& o) : v (o.get_relaxed ()) { o.set_relaxed ({}); }
hb_atomic_t &operator= (const hb_atomic_t& o) { set_relaxed (o.get_relaxed ()); return *this; }
hb_atomic_t &operator= (hb_atomic_t&& o){ set_relaxed (o.get_relaxed ()); o.set_relaxed ({}); return *this; }
hb_atomic_t &operator= (T v_)
{
set_relaxed (v_);
return *this;
}
operator T () const { return get_relaxed (); }
void set_relaxed (T v_) { v.store (v_, std::memory_order_relaxed); }
void set_release (T v_) { v.store (v_, std::memory_order_release); }
T get_relaxed () const { return v.load (std::memory_order_relaxed); }
T get_acquire () const { return v.load (std::memory_order_acquire); }
T inc () { return v.fetch_add (1, std::memory_order_acq_rel); }
T dec () { return v.fetch_add (-1, std::memory_order_acq_rel); }
int operator++ (int) { return inc (); }
int operator-- (int) { return dec (); }
long operator|= (long v_)
{
set_relaxed (get_relaxed () | v_);
return *this;
}
friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept
{
T v = a.get_acquire ();
a.set_relaxed (b.get_acquire ());
b.set_relaxed (v);
}
std::atomic<T> v = 0;
};
template <typename T>
struct hb_atomic_t<T *>
{
hb_atomic_t () = default;
constexpr hb_atomic_t (T *v) : v (v) {}
hb_atomic_t (const hb_atomic_t &other) = delete;
void init (T *v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T *v_) { v.store (v_, std::memory_order_relaxed); }
T *get_relaxed () const { return v.load (std::memory_order_relaxed); }
T *get_acquire () const { return v.load (std::memory_order_acquire); }
bool cmpexch (T *old, T *new_) { return v.compare_exchange_weak (old, new_, std::memory_order_acq_rel, std::memory_order_relaxed); }
operator bool () const { return get_acquire () != nullptr; }
T *operator->() const { return get_acquire (); }
template <typename C>
operator C * () const
{
return get_acquire ();
}
friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept
{
T *p = a.get_acquire ();
a.set_relaxed (b.get_acquire ());
b.set_relaxed (p);
}
std::atomic<T *> v = nullptr;
};
#else
template <typename T>
struct hb_atomic_t
{
hb_atomic_t () = default;
constexpr hb_atomic_t (T v) : v (v) {}
hb_atomic_t& operator = (T v_) { set_relaxed (v_); return *this; }
operator T () const { return get_relaxed (); }
void set_relaxed (T v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set_release (T v_) { hb_atomic_int_impl_set (&v, v_); }
T get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
T get_acquire () const { return hb_atomic_int_impl_get (&v); }
T inc () { return hb_atomic_int_impl_add (&v, 1); }
T dec () { return hb_atomic_int_impl_add (&v, -1); }
int operator ++ (int) { return inc (); }
int operator -- (int) { return dec (); }
long operator |= (long v_) { set_relaxed (get_relaxed () | v_); return *this; }
T v = 0;
};
template <typename T>
struct hb_atomic_t<T*>
{
hb_atomic_t () = default;
constexpr hb_atomic_t (T* v) : v (v) {}
hb_atomic_t (const hb_atomic_t &other) = delete;
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
bool cmpexch (T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
operator bool () const { return get_acquire () != nullptr; }
T * operator -> () const { return get_acquire (); }
template <typename C> operator C * () const { return get_acquire (); }
T *v = nullptr;
};
#endif
static inline bool hb_barrier ()
{
_hb_compiler_memory_r_barrier ();
return true;
}
#endif /* HB_ATOMIC_HH */