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

Andrej Shadura via libcxx-commits libcxx-commits at lists.llvm.org
Fri Nov 15 07:10:13 PST 2024


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

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 at collabora.co.uk>

>From c4ae884a0bbeb65a23706f4d13d22d32fed6ecc6 Mon Sep 17 00:00:00 2001
From: Grace Cham <hscham at chromium.org>
Date: Tue, 16 Jul 2024 23:17:37 +0000
Subject: [PATCH] [libc++] Crash when dereferencing an empty std::optional

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 at collabora.co.uk>
---
 libcxx/include/optional | 38 ++++++++++++++++++++++++++++++++------
 1 file changed, 32 insertions(+), 6 deletions(-)

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());
   }
 



More information about the libcxx-commits mailing list