Skip to content

Commit 8dad44d

Browse files
committed
[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) ```
1 parent 37123e9 commit 8dad44d

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

libcxx/include/variant

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,10 @@ namespace std {
261261
#include <new>
262262
#include <version>
263263

264+
#if __has_feature(memory_sanitizer)
265+
# include <sanitizer/msan_interface.h>
266+
#endif
267+
264268
// standard-mandated includes
265269

266270
// [variant.syn]
@@ -781,6 +785,10 @@ _LIBCPP_VARIANT_DESTRUCTOR(
781785
_Trait::_TriviallyAvailable,
782786
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__dtor() = default,
783787
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __destroy() noexcept {
788+
# if __has_feature(memory_sanitizer)
789+
if (!std::is_constant_evaluated())
790+
__sanitizer_dtor_callback(&this->__data, sizeof(this->__data));
791+
# endif
784792
this->__index = __variant_npos<__index_t>;
785793
} _LIBCPP_EAT_SEMICOLON);
786794

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14
10+
11+
// <variant>
12+
13+
// template <class ...Types> class variant;
14+
15+
#include <variant>
16+
17+
#if __has_feature(memory_sanitizer)
18+
# include <sanitizer/msan_interface.h>
19+
#endif
20+
21+
int main(int, char**) {
22+
#if __has_feature(memory_sanitizer)
23+
std::variant<double, int> v;
24+
v.emplace<double>();
25+
double& d = std::get<double>(v);
26+
v.emplace<int>();
27+
if (__msan_test_shadow(&d, sizeof(d)) == -1) {
28+
// Unexpected: The entire range is accessible.
29+
return 1;
30+
}
31+
#endif
32+
33+
return 0;
34+
}

0 commit comments

Comments
 (0)