From 6b062584e56fe395be723220324ea384bf447971 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Mon, 3 Jul 2023 22:17:06 +0200 Subject: option: fix UB, launder value ptr --- option.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'option.h') diff --git a/option.h b/option.h index b9ebe2f..fd26acb 100644 --- a/option.h +++ b/option.h @@ -18,7 +18,7 @@ using enable_if_t = typename std::enable_if::type; /// The NONE type. struct none {}; -// The OPTION type. +/// The OPTION type. template struct option { static_assert(!std::is_reference::value, "T must not be a reference type"); @@ -87,12 +87,25 @@ struct option { constexpr T& value() & { assert(m_has_value); - return *reinterpret_cast(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(m_value)); } constexpr const T& value() const& { assert(m_has_value); - return *reinterpret_cast(m_value); + // Launder, see other value(). + return *__builtin_launder(reinterpret_cast(m_value)); } constexpr T value() && { -- cgit v1.2.3