[libcxx-commits] [libcxx] [libc++] Crash when dereferencing an empty std::optional (PR #116394)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Nov 15 22:28:23 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Andrej Shadura (andrewshadura)

<details>
<summary>Changes</summary>

Dereferencing a std::optional that does not contain a value is undefined behaviour. It is better to crash when this happens to prevent potential abuse or a crash further down the line.

[reworded the commit message]
Co-Authored-By: Andrej Shadura <andrew.shadura@<!-- -->collabora.co.uk>

---
Full diff: https://github.com/llvm/llvm-project/pull/116394.diff


1 Files Affected:

- (modified) libcxx/include/optional (+32-6) 


``````````diff
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 7ad6a9e116941f..71c0eabed446dc 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -177,6 +177,8 @@ namespace std {
 
 */
 
+#include <stdio.h>
+
 #include <__assert>
 #include <__compare/compare_three_way_result.h>
 #include <__compare/ordering.h>
@@ -791,33 +793,57 @@ public:
     }
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<value_type const> operator->() const noexcept {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS constexpr add_pointer_t<value_type const> operator->() const noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
+        if (!this->has_value()) {
+          fprintf(stderr, "optional operator-> called on a disengaged value\n");
+          __builtin_trap();
+        }
     return std::addressof(this->__get());
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<value_type> operator->() noexcept {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS constexpr add_pointer_t<value_type> operator->() noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
+        if (!this->has_value()) {
+          fprintf(stderr, "optional operator-> called on a disengaged value\n");
+          __builtin_trap();
+        }
     return std::addressof(this->__get());
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const value_type& operator*() const& noexcept {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS constexpr const value_type& operator*() const& noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+        if (!this->has_value()) {
+          fprintf(stderr, "optional operator-> called on a disengaged value\n");
+          __builtin_trap();
+        }
     return this->__get();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr value_type& operator*() & noexcept {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS constexpr value_type& operator*() & noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+        if (!this->has_value()) {
+          fprintf(stderr, "optional operator-> called on a disengaged value\n");
+          __builtin_trap();
+        }
     return this->__get();
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr value_type&& operator*() && noexcept {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS constexpr value_type&& operator*() && noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+        if (!this->has_value()) {
+          fprintf(stderr, "optional operator-> called on a disengaged value\n");
+          __builtin_trap();
+        }
     return std::move(this->__get());
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const value_type&& operator*() const&& noexcept {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS constexpr const value_type&& operator*() const&& noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+        if (!this->has_value()) {
+          fprintf(stderr, "optional operator-> called on a disengaged value\n");
+          __builtin_trap();
+        }
     return std::move(this->__get());
   }
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/116394


More information about the libcxx-commits mailing list