diff options
author | Johannes Stoelp <johannes.stoelp@gmail.com> | 2023-07-03 22:17:06 +0200 |
---|---|---|
committer | Johannes Stoelp <johannes.stoelp@gmail.com> | 2023-07-03 22:17:06 +0200 |
commit | 6b062584e56fe395be723220324ea384bf447971 (patch) | |
tree | 604b80b2fd8f9e5a2dcd5fda5e51920a7acb119d | |
parent | 07c77d4c24177ac3e11cafd27f34c9a758008db6 (diff) | |
download | cpp-utils-6b062584e56fe395be723220324ea384bf447971.tar.gz cpp-utils-6b062584e56fe395be723220324ea384bf447971.zip |
option: fix UB, launder value ptr
-rw-r--r-- | option.h | 19 |
1 files changed, 16 insertions, 3 deletions
@@ -18,7 +18,7 @@ using enable_if_t = typename std::enable_if<Cond, T>::type; /// The NONE type. struct none {}; -// The OPTION type. +/// The OPTION type. template <typename T> struct option { static_assert(!std::is_reference<T>::value, "T must not be a reference type"); @@ -87,12 +87,25 @@ struct option { constexpr T& value() & { assert(m_has_value); - return *reinterpret_cast<T*>(m_value); + // Launder pointer, this informs the compiler that certain optimizations are + // not applicable such as CONSTPROP. This is required because every use + // of PLACEMENT new on M_VALUE starts a new LIFETIME and returning a + // pointer based on the LIFETIME of M_VALUE is UB [1][2]. + // + // Notes: + // * Obtaining a pointer to an object created by placement new from a + // pointer to an object providing storage for that object [1]. + // * See example in [1] and [2]. + // + // [1]: https://en.cppreference.com/w/cpp/utility/launder + // [2]: https://en.cppreference.com/w/cpp/types/aligned_storage + return *__builtin_launder(reinterpret_cast<T*>(m_value)); } constexpr const T& value() const& { assert(m_has_value); - return *reinterpret_cast<const T*>(m_value); + // Launder, see other value(). + return *__builtin_launder(reinterpret_cast<const T*>(m_value)); } constexpr T value() && { |