[libcxx-commits] [libcxx] Poison memory in variant destroy (PR #101048)

Chris Cotter via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jul 29 11:56:34 PDT 2024


https://github.com/ccotter updated https://github.com/llvm/llvm-project/pull/101048

>From 18cf97d3c32ece34af0b3a32d2b674ae840f66a2 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotter14 at bloomberg.net>
Date: Mon, 29 Jul 2024 13:25:39 -0400
Subject: [PATCH] [libcxx] Poison memory in variant destroy

In the version of `__destroy` that does not destruct any part of
`__data`, MSAN is unable to see that `__data` is logically
uninitialized. This allows false negatives such as the following to
run without any MSAN diagnostic.

```
std::variant<double, int> v;
v.emplace<double>();
double& d = std::get<double>(v);
v.emplace<int>();
if (d) ...
```

With these changes, MSAN reports uninitialized memory:

```
==32202==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x5557b64820aa in main /home/ccotter/variant_msan.cpp:19:9
    #1 0x7fbfacd88554 in __libc_start_main /usr/src/debug/glibc-2.17-c758a686/csu/../csu/libc-start.c:266
    #2 0x5557b63ed40d in _start (/home/ccotter/a.out+0x3140d)
```
---
 libcxx/include/variant                        |  8 ++++
 .../variant.variant/variant_msan.pass.cpp     | 43 +++++++++++++++++++
 2 files changed, 51 insertions(+)
 create mode 100644 libcxx/test/std/utilities/variant/variant.variant/variant_msan.pass.cpp

diff --git a/libcxx/include/variant b/libcxx/include/variant
index 631ffceab5f68f..99e954092e30d0 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -261,6 +261,10 @@ namespace std {
 #include <new>
 #include <version>
 
+#if __has_feature(memory_sanitizer)
+#  include <sanitizer/msan_interface.h>
+#endif
+
 // standard-mandated includes
 
 // [variant.syn]
@@ -781,6 +785,10 @@ _LIBCPP_VARIANT_DESTRUCTOR(
     _Trait::_TriviallyAvailable,
     _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__dtor() = default,
     _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __destroy() noexcept {
+#  if __has_feature(memory_sanitizer)
+    if (!std::is_constant_evaluated())
+      __sanitizer_dtor_callback(&this->__data, sizeof(this->__data));
+#  endif
       this->__index = __variant_npos<__index_t>;
     } _LIBCPP_EAT_SEMICOLON);
 
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant_msan.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant_msan.pass.cpp
new file mode 100644
index 00000000000000..1548238152d32a
--- /dev/null
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant_msan.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// <variant>
+
+// template <class ...Types> class variant;
+
+
+#include <variant>
+#include <type_traits>
+#include <string>
+#include <cassert>
+
+#include "test_macros.h"
+#include "variant_test_helpers.h"
+#include "test_convertible.h"
+
+#if __has_feature(memory_sanitizer)
+#include <sanitizer/msan_interface.h>
+#endif
+
+int main(int, char**)
+{
+#if __has_feature(memory_sanitizer)
+    std::variant<double, int> v;
+    v.emplace<double>();
+    double& d = std::get<double>(v);
+    v.emplace<int>();
+    if (__msan_test_shadow(&d, sizeof(d)) == -1) {
+        // Unexpected: The entire range is accessible.
+        return 1;
+    }
+#endif
+
+    return 0;
+}



More information about the libcxx-commits mailing list