Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Destructor Tombstones #5318

Merged
merged 18 commits into from
Mar 3, 2025
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