Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions stl/inc/any
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ public:

~any() noexcept {
reset();

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
// _Small mode will prevent the most misuse, as the pseudo-vtable will be used for _Destroy, _Copy, and _Move.
// _Big mode wouldn't use the pseudo-vtable for _Move, and _Trivial mode doesn't have a pseudo-vtable at all.
const uintptr_t _Tombstone_value{_MSVC_STL_UINTPTR_TOMBSTONE_VALUE};
_Storage._SmallStorage._RTTI = reinterpret_cast<const _Any_small_RTTI*>(_Tombstone_value);
_Storage._TypeData = (_Tombstone_value & ~_Rep_mask) | static_cast<uintptr_t>(_Any_representation::_Small);
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES
}

// Assignment [any.assign]
Expand Down
12 changes: 12 additions & 0 deletions stl/inc/deque
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,18 @@ public:

_Deque_val() noexcept : _Map(), _Mapsize(0), _Myoff(0), _Mysize(0) {}

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
~_Deque_val() noexcept {
if constexpr (is_pointer_v<_Mapptr>) {
const auto _Tombstone{reinterpret_cast<_Mapptr>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Map = _Tombstone;
_Mapsize = 0;
_Myoff = 0;
_Mysize = 0;
}
}
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES

_Map_difference_type _Getblock(size_type _Off) const noexcept {
// NB: _Mapsize and _Block_size are guaranteed to be powers of 2
return static_cast<_Map_difference_type>((_Off / _Block_size) & (_Mapsize - 1));
Expand Down
6 changes: 6 additions & 0 deletions stl/inc/exception
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ public:

~exception_ptr() noexcept {
__ExceptionPtrDestroy(this);

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
const auto _Tombstone{reinterpret_cast<void*>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Data1 = _Tombstone;
_Data2 = _Tombstone;
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES
}

exception_ptr(const exception_ptr& _Rhs) noexcept {
Expand Down
9 changes: 9 additions & 0 deletions stl/inc/forward_list
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,15 @@ public:

_Flist_val() noexcept : _Myhead() {} // initialize data

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
~_Flist_val() noexcept {
if constexpr (is_pointer_v<_Nodeptr>) {
const auto _Tombstone{reinterpret_cast<_Nodeptr>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Myhead = _Tombstone;
}
}
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES

_Nodeptr _Before_head() const noexcept { // return pointer to the "before begin" pseudo node
return pointer_traits<_Nodeptr>::pointer_to(reinterpret_cast<_Node&>(const_cast<_Nodeptr&>(_Myhead)));
}
Expand Down
10 changes: 10 additions & 0 deletions stl/inc/functional
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,11 @@ public:

~_Func_class() noexcept {
_Tidy();

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
const auto _Tombstone{reinterpret_cast<_Ptrt*>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Set(_Tombstone);
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES
}

protected:
Expand Down Expand Up @@ -1934,6 +1939,11 @@ public:
// Do cleanup in this class destructor rather than base,
// so that if object construction throws, the unnecessary cleanup isn't called.
this->_Checked_destroy(this->_Data);

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
const auto _Tombstone{reinterpret_cast<const void*>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
this->_Data._Impl = _Tombstone;
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES
}

move_only_function& operator=(nullptr_t) noexcept {
Expand Down
10 changes: 10 additions & 0 deletions stl/inc/list
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,16 @@ public:

_List_val() noexcept : _Myhead(), _Mysize(0) {} // initialize data

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
~_List_val() noexcept {
if constexpr (is_pointer_v<_Nodeptr>) {
const auto _Tombstone{reinterpret_cast<_Nodeptr>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Myhead = _Tombstone;
_Mysize = 0;
}
}
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES

void _Orphan_ptr2(_Nodeptr _Ptr) noexcept { // orphan iterators with specified node pointers
#if _ITERATOR_DEBUG_LEVEL == 2
_Lockit _Lock(_LOCK_DEBUG);
Expand Down
26 changes: 26 additions & 0 deletions stl/inc/memory
Original file line number Diff line number Diff line change
Expand Up @@ -1311,7 +1311,15 @@ protected:

constexpr _Ptr_base() noexcept = default;

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
~_Ptr_base() noexcept {
const uintptr_t _Tombstone_value{_MSVC_STL_UINTPTR_TOMBSTONE_VALUE};
_Ptr = reinterpret_cast<element_type*>(_Tombstone_value);
_Rep = reinterpret_cast<_Ref_count_base*>(_Tombstone_value);
}
#else // ^^^ _MSVC_STL_DESTRUCTOR_TOMBSTONES / !_MSVC_STL_DESTRUCTOR_TOMBSTONES vvv
~_Ptr_base() = default;
#endif // ^^^ !_MSVC_STL_DESTRUCTOR_TOMBSTONES ^^^

template <class _Ty2>
void _Move_construct_from(_Ptr_base<_Ty2>&& _Right) noexcept {
Expand Down Expand Up @@ -3418,6 +3426,15 @@ public:
if (_Mypair._Myval2) {
_Mypair._Get_first()(_Mypair._Myval2);
}

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
if constexpr (is_pointer_v<pointer>) {
if (!_STD _Is_constant_evaluated()) {
const auto _Tombstone{reinterpret_cast<pointer>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Mypair._Myval2 = _Tombstone;
}
}
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES
}

_NODISCARD _CONSTEXPR23 _Dx& get_deleter() noexcept {
Expand Down Expand Up @@ -3555,6 +3572,15 @@ public:
if (_Mypair._Myval2) {
_Mypair._Get_first()(_Mypair._Myval2);
}

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
if constexpr (is_pointer_v<pointer>) {
if (!_STD _Is_constant_evaluated()) {
const auto _Tombstone{reinterpret_cast<pointer>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Mypair._Myval2 = _Tombstone;
}
}
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES
}

_NODISCARD _CONSTEXPR23 _Dx& get_deleter() noexcept {
Expand Down
7 changes: 7 additions & 0 deletions stl/inc/optional
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ struct _Optional_destruct_base { // either contains a value of _Ty or is empty (
: _Value(_STD invoke(_STD forward<_Fn>(_Func), _STD forward<_Ux>(_Arg))), _Has_value{true} {}
#endif // _HAS_CXX23

// N5001 [optional.dtor]/2: "Remarks: If is_trivially_destructible_v<T> is true, then this destructor is trivial."
// This prevents us from adding a destructor to the trivial case for _MSVC_STL_DESTRUCTOR_TOMBSTONES.

_CONSTEXPR20 void reset() noexcept {
_Has_value = false;
}
Expand All @@ -104,6 +107,10 @@ struct _Optional_destruct_base<_Ty, false> { // either contains a value of _Ty o
_CONSTEXPR20 ~_Optional_destruct_base() noexcept {
if (_Has_value) {
_Value.~_Ty();

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
_Has_value = false;
#endif
}
}

Expand Down
5 changes: 5 additions & 0 deletions stl/inc/regex
Original file line number Diff line number Diff line change
Expand Up @@ -1923,6 +1923,11 @@ public:

~basic_regex() noexcept {
_Tidy();

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
const auto _Tombstone{reinterpret_cast<_Root_node*>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Rep = _Tombstone;
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES
}

basic_regex& operator=(const basic_regex& _Right) {
Expand Down
6 changes: 6 additions & 0 deletions stl/inc/valarray
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ public:

~valarray() noexcept {
_Tidy_deallocate();

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
// _Tidy_deallocate() sets _Mysize to 0.
const auto _Tombstone{reinterpret_cast<_Ty*>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Myptr = _Tombstone;
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES
}

valarray& operator=(const valarray& _Right) {
Expand Down
8 changes: 8 additions & 0 deletions stl/inc/variant
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,10 @@ public:
_Which{static_cast<_Index_t>(_Idx)} { // initialize alternative _Idx from _Args...
}

// N5001 [variant.dtor]/2: "Remarks: If is_trivially_destructible_v<Ti> is true for all Ti,
// then this destructor is trivial."
// This prevents us from adding a destructor to the trivial case for _MSVC_STL_DESTRUCTOR_TOMBSTONES.

_NODISCARD constexpr bool valueless_by_exception() const noexcept { // does this variant NOT hold a value?
return _Which < 0;
}
Expand Down Expand Up @@ -839,6 +843,10 @@ struct _Variant_destroy_layer_ : _Variant_base<_Types...> { // destruction behav

_CONSTEXPR20 ~_Variant_destroy_layer_() noexcept { // Destroy contained value, if any
this->_Destroy();

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
this->_Set_index(variant_npos);
#endif
}

_Variant_destroy_layer_() = default;
Expand Down
17 changes: 17 additions & 0 deletions stl/inc/vector
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,19 @@ public:
_CONSTEXPR20 _Vector_val(pointer _First, pointer _Last, pointer _End) noexcept
: _Myfirst(_First), _Mylast(_Last), _Myend(_End) {}

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
_CONSTEXPR20 ~_Vector_val() noexcept {
if constexpr (is_pointer_v<pointer>) {
if (!_STD _Is_constant_evaluated()) {
const auto _Tombstone{reinterpret_cast<pointer>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Myfirst = _Tombstone;
_Mylast = _Tombstone;
_Myend = _Tombstone;
}
}
}
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES

_CONSTEXPR20 void _Swap_val(_Vector_val& _Right) noexcept {
this->_Swap_proxy_and_iterators(_Right);
swap(_Myfirst, _Right._Myfirst); // intentional ADL
Expand Down Expand Up @@ -2851,6 +2864,10 @@ public:
auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alvbase, this->_Getal());
_Delete_plain_internal(_Alproxy, _STD exchange(this->_Myproxy, nullptr));
#endif // _ITERATOR_DEBUG_LEVEL != 0

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
_Mysize = 0;
#endif
}

_CONSTEXPR20 _Alvbase& _Getal() noexcept {
Expand Down
7 changes: 7 additions & 0 deletions stl/inc/xhash
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,13 @@ public:
#endif // _ENABLE_STL_INTERNAL_CHECK
}

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
~_Hash() noexcept {
_Mask = _Min_buckets - 1;
_Maxidx = _Min_buckets;
}
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES

private:
void _Swap_val(_Hash& _Right) noexcept { // swap contents with equal allocator _Hash _Right
_List._Swap_val(_Right._List);
Expand Down
7 changes: 7 additions & 0 deletions stl/inc/xpolymorphic_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,13 @@ namespace pmr {

polymorphic_allocator& operator=(const polymorphic_allocator&) = delete;

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
~polymorphic_allocator() noexcept {
const auto _Tombstone{reinterpret_cast<memory_resource*>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Resource = _Tombstone;
}
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES

_NODISCARD_RAW_PTR_ALLOC __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count) {
// get space for _Count objects of type _Ty from _Resource
void* const _Vp = _Resource->allocate(_Get_size_of_n<sizeof(_Ty)>(_Count), alignof(_Ty));
Expand Down
13 changes: 13 additions & 0 deletions stl/inc/xstring
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,19 @@ public:

_CONSTEXPR20 _String_val() noexcept : _Bx() {}

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
_CONSTEXPR20 ~_String_val() noexcept {
if constexpr (is_pointer_v<pointer>) {
if (!_STD _Is_constant_evaluated()) {
const auto _Tombstone{reinterpret_cast<pointer>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Bx._Ptr = _Tombstone;
_Mysize = 0;
_Myres = (_Small_string_capacity + 1) | _Alloc_mask; // first capacity when entering large mode
}
}
}
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES

// length of internal buffer, [1, 16] (NB: used by the debugger visualizer)
static constexpr size_type _BUF_SIZE = 16 / sizeof(value_type) < 1 ? 1 : 16 / sizeof(value_type);
// roundup mask for allocated buffers, [0, 15]
Expand Down
10 changes: 10 additions & 0 deletions stl/inc/xtree
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,16 @@ public:

_Tree_val() noexcept : _Myhead(), _Mysize(0) {}

#if _MSVC_STL_DESTRUCTOR_TOMBSTONES
~_Tree_val() noexcept {
if constexpr (is_pointer_v<_Nodeptr>) {
const auto _Tombstone{reinterpret_cast<_Nodeptr>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)};
_Myhead = _Tombstone;
_Mysize = 0;
}
}
#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES

enum _Redbl { // colors for link to parent
_Red,
_Black
Expand Down
8 changes: 8 additions & 0 deletions stl/inc/yvals.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,14 @@ _EMIT_STL_ERROR(STL1008, "_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER has been
#define _STL_INTERNAL_CHECK(...) _Analysis_assume_(__VA_ARGS__)
#endif // ^^^ !defined(_ENABLE_STL_INTERNAL_CHECK) ^^^

#ifndef _MSVC_STL_DESTRUCTOR_TOMBSTONES
#define _MSVC_STL_DESTRUCTOR_TOMBSTONES 0
#endif

#ifndef _MSVC_STL_UINTPTR_TOMBSTONE_VALUE
#define _MSVC_STL_UINTPTR_TOMBSTONE_VALUE uintptr_t{19937}
#endif

#include <use_ansi.h>

#ifdef _STATIC_CPPLIB
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ tests\GH_004845_logical_operator_traits_with_non_bool_constant
tests\GH_004929_internal_tag_constructors
tests\GH_004930_char_traits_user_specialization
tests\GH_005090_stl_hardening
tests\GH_005315_destructor_tombstones
tests\LWG2381_num_get_floating_point
tests\LWG2597_complex_branch_cut
tests\LWG3018_shared_ptr_function
Expand Down
6 changes: 6 additions & 0 deletions tests/std/tests/GH_005315_destructor_tombstones/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_matrix.lst
RUNALL_CROSSLIST
* PM_CL="/D_MSVC_STL_DESTRUCTOR_TOMBSTONES=1"
Loading