Skip to content

Commit 18cf97d

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 b7ed097 commit 18cf97d

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-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: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
16+
#include <variant>
17+
#include <type_traits>
18+
#include <string>
19+
#include <cassert>
20+
21+
#include "test_macros.h"
22+
#include "variant_test_helpers.h"
23+
#include "test_convertible.h"
24+
25+
#if __has_feature(memory_sanitizer)
26+
#include <sanitizer/msan_interface.h>
27+
#endif
28+
29+
int main(int, char**)
30+
{
31+
#if __has_feature(memory_sanitizer)
32+
std::variant<double, int> v;
33+
v.emplace<double>();
34+
double& d = std::get<double>(v);
35+
v.emplace<int>();
36+
if (__msan_test_shadow(&d, sizeof(d)) == -1) {
37+
// Unexpected: The entire range is accessible.
38+
return 1;
39+
}
40+
#endif
41+
42+
return 0;
43+
}

0 commit comments

Comments
 (0)