зеркало из https://github.com/microsoft/STL.git
`<vector>`: Add ASan annotations. (#2071)
Co-authored-by: Casey Carter <cartec69@gmail.com> Co-authored-by: Michael Schellenberger Costa <mschellenbergercosta@googlemail.com> Co-authored-by: Stephan T. Lavavej <stl@microsoft.com>
This commit is contained in:
Родитель
5e3574b979
Коммит
2f9f567ffe
|
@ -250,6 +250,7 @@ endforeach()
|
|||
|
||||
# Objs that exist in both libcpmt[d][01].lib and msvcprt[d].lib.
|
||||
set(IMPLIB_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/asan_noop.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/filesystem.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/format.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/locale0_implib.cpp
|
||||
|
@ -392,6 +393,10 @@ set(SOURCES
|
|||
${CMAKE_CURRENT_LIST_DIR}/src/xwstoxfl.cpp
|
||||
)
|
||||
|
||||
set(ASAN_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/asan.cpp
|
||||
)
|
||||
|
||||
set(EHA_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/excptptr.cpp
|
||||
)
|
||||
|
@ -543,11 +548,11 @@ add_stl_dlls("d" "_DEBUG" "${VCLIBS_DEBUG_OPTIONS}" "" "/opt:ref,noicf")
|
|||
|
||||
function(add_stl_statics FLAVOR_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIONS)
|
||||
add_library(libcpmt${FLAVOR_SUFFIX}_eha OBJECT ${EHA_SOURCES})
|
||||
target_compile_definitions(libcpmt${FLAVOR_SUFFIX}_eha PRIVATE "${THIS_CONFIG_DEFINITIONS}")
|
||||
target_compile_definitions(libcpmt${FLAVOR_SUFFIX}_eha PRIVATE "${THIS_CONFIG_DEFINITIONS};_ANNOTATE_VECTOR")
|
||||
target_compile_options(libcpmt${FLAVOR_SUFFIX}_eha PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};/EHa")
|
||||
|
||||
add_library(libcpmt${FLAVOR_SUFFIX} STATIC ${HEADERS} ${IMPLIB_SOURCES} ${SOURCES} ${INITIALIZER_SOURCES} ${STATIC_SOURCES})
|
||||
target_compile_definitions(libcpmt${FLAVOR_SUFFIX} PRIVATE "${THIS_CONFIG_DEFINITIONS}")
|
||||
target_compile_definitions(libcpmt${FLAVOR_SUFFIX} PRIVATE "${THIS_CONFIG_DEFINITIONS};_ANNOTATE_VECTOR")
|
||||
target_compile_options(libcpmt${FLAVOR_SUFFIX} PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};/EHsc")
|
||||
target_link_libraries(libcpmt${FLAVOR_SUFFIX} PRIVATE Boost::math libcpmt${FLAVOR_SUFFIX}_eha std_init_once_begin_initialize std_init_once_complete)
|
||||
endfunction()
|
||||
|
@ -557,3 +562,5 @@ add_stl_statics("1" "_ITERATOR_DEBUG_LEVEL=1" "${VCLIBS_RELEASE_OPTIONS}")
|
|||
add_stl_statics("d" "_DEBUG;_ITERATOR_DEBUG_LEVEL=2" "${VCLIBS_DEBUG_OPTIONS}")
|
||||
add_stl_statics("d1" "_DEBUG;_ITERATOR_DEBUG_LEVEL=1" "${VCLIBS_DEBUG_OPTIONS}")
|
||||
add_stl_statics("d0" "_DEBUG;_ITERATOR_DEBUG_LEVEL=0" "${VCLIBS_DEBUG_OPTIONS}")
|
||||
|
||||
add_library(stl_asan STATIC ${ASAN_SOURCES})
|
||||
|
|
368
stl/inc/vector
368
stl/inc/vector
|
@ -428,6 +428,54 @@ constexpr _Ty* _Unfancy_maybe_null(_Ty* _Ptr) noexcept { // do nothing for plain
|
|||
return _Ptr;
|
||||
}
|
||||
|
||||
#if !defined(_M_CEE_PURE) && !defined(_DISABLE_VECTOR_ANNOTATION)
|
||||
#if defined(__SANITIZE_ADDRESS__)
|
||||
#define _ACTIVATE_VECTOR_ANNOTATION
|
||||
#define _INSERT_VECTOR_ANNOTATION
|
||||
#elif defined(__clang__) && defined(__has_feature) // ^^^ __SANITIZE_ADDRESS__ ^^^ // vvv __clang__ vvv
|
||||
#if __has_feature(address_sanitizer)
|
||||
#define _ACTIVATE_VECTOR_ANNOTATION
|
||||
#define _INSERT_VECTOR_ANNOTATION
|
||||
#pragma comment(linker, "/INFERASANLIBS")
|
||||
#endif // __has_feature(address_sanitizer)
|
||||
#elif defined(_ANNOTATE_VECTOR) // ^^^ __clang__ ^^^ // vvv _ANNOTATE_VECTOR vvv
|
||||
#define _INSERT_VECTOR_ANNOTATION
|
||||
#endif // _ANNOTATE_VECTOR
|
||||
#endif // !_M_CEE_PURE && !_DISABLE_VECTOR_ANNOTATION
|
||||
|
||||
#ifdef _ACTIVATE_VECTOR_ANNOTATION
|
||||
#pragma comment(lib, "stl_asan")
|
||||
#pragma detect_mismatch("annotate_vector", "1")
|
||||
#endif // _ACTIVATE_VECTOR_ANNOTATION
|
||||
|
||||
#ifdef _INSERT_VECTOR_ANNOTATION
|
||||
extern "C" {
|
||||
void __cdecl __sanitizer_annotate_contiguous_container(
|
||||
const void* _First, const void* _End, const void* _Old_last, const void* _New_last) noexcept;
|
||||
extern const bool _Asan_vector_should_annotate;
|
||||
}
|
||||
|
||||
#if defined(_M_IX86)
|
||||
#pragma comment(linker, \
|
||||
"/alternatename:___sanitizer_annotate_contiguous_container=___sanitizer_annotate_contiguous_container_default")
|
||||
#pragma comment(linker, "/alternatename:__Asan_vector_should_annotate=__Asan_vector_should_annotate_default")
|
||||
#elif defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64)
|
||||
#pragma comment(linker, \
|
||||
"/alternatename:__sanitizer_annotate_contiguous_container=__sanitizer_annotate_contiguous_container_default")
|
||||
#pragma comment(linker, "/alternatename:_Asan_vector_should_annotate=_Asan_vector_should_annotate_default")
|
||||
#endif
|
||||
|
||||
template <class _Vec, class = void>
|
||||
_INLINE_VAR constexpr bool _Has_minimum_allocation_alignment = alignof(typename _Vec::value_type) >= _Asan_granularity;
|
||||
|
||||
template <class _Vec>
|
||||
_INLINE_VAR constexpr bool
|
||||
_Has_minimum_allocation_alignment<_Vec, void_t<decltype(_Vec::allocator_type::_Minimum_allocation_alignment)>> =
|
||||
_Vec::allocator_type::_Minimum_allocation_alignment >= _Asan_granularity;
|
||||
#else // ^^^ _INSERT_VECTOR_ANNOTATION ^^^ // vvv !_INSERT_VECTOR_ANNOTATION vvv
|
||||
#pragma detect_mismatch("annotate_vector", "0")
|
||||
#endif // !_INSERT_VECTOR_ANNOTATION
|
||||
|
||||
template <class _Ty, class _Alloc = allocator<_Ty>>
|
||||
class vector { // varying size array of values
|
||||
private:
|
||||
|
@ -452,6 +500,142 @@ public:
|
|||
using difference_type = typename _Alty_traits::difference_type;
|
||||
|
||||
private:
|
||||
#ifdef _INSERT_VECTOR_ANNOTATION
|
||||
_CONSTEXPR20 void _Create_annotation() const noexcept {
|
||||
// Annotates the shadow memory of the valid range
|
||||
auto& _My_data = _Mypair._Myval2;
|
||||
_Apply_annotation(_My_data._Myfirst, _My_data._Myend, _My_data._Myend, _My_data._Mylast);
|
||||
}
|
||||
|
||||
_CONSTEXPR20 void _Remove_annotation() const noexcept {
|
||||
// Removes the shadow memory annotation of the range
|
||||
auto& _My_data = _Mypair._Myval2;
|
||||
_Apply_annotation(_My_data._Myfirst, _My_data._Myend, _My_data._Mylast, _My_data._Myend);
|
||||
}
|
||||
|
||||
_CONSTEXPR20 void _Modify_annotation(const difference_type _Count) const noexcept {
|
||||
// Extends/shrinks the annotated range by _Count
|
||||
auto& _My_data = _Mypair._Myval2;
|
||||
_Apply_annotation(_My_data._Myfirst, _My_data._Myend, _My_data._Mylast, _My_data._Mylast + _Count);
|
||||
}
|
||||
|
||||
_NODISCARD static const void* _Get_aligned_first(const void* _First, const void* _End) noexcept {
|
||||
const auto _CFirst = reinterpret_cast<const char*>(_First);
|
||||
const auto _CEnd = reinterpret_cast<const char*>(_End);
|
||||
const size_t _Capacity = static_cast<size_t>(_CEnd - _CFirst);
|
||||
|
||||
if (_Capacity >= _Asan_granularity) {
|
||||
// We are guaranteed to have sufficient space to find an aligned address.
|
||||
return reinterpret_cast<const void*>(
|
||||
(reinterpret_cast<uintptr_t>(_CFirst) + (_Asan_granularity - 1)) & ~(_Asan_granularity - 1));
|
||||
}
|
||||
|
||||
uintptr_t _Alignment_offset = reinterpret_cast<uintptr_t>(_CFirst) & (_Asan_granularity - 1);
|
||||
if (_Alignment_offset != 0) {
|
||||
_Alignment_offset = _Asan_granularity - _Alignment_offset;
|
||||
}
|
||||
|
||||
if (_Capacity > _Alignment_offset) {
|
||||
return _CFirst + _Alignment_offset;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static _CONSTEXPR20 void _Apply_annotation(
|
||||
pointer _First_, pointer _End_, pointer _Old_last_, pointer _New_last_) noexcept {
|
||||
#if _HAS_CXX20
|
||||
if (_STD is_constant_evaluated()) {
|
||||
return;
|
||||
}
|
||||
#endif // _HAS_CXX20
|
||||
|
||||
if (!_Asan_vector_should_annotate) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto _First = reinterpret_cast<const char*>(_Unfancy_maybe_null(_First_));
|
||||
const auto _End = reinterpret_cast<const char*>(_Unfancy_maybe_null(_End_));
|
||||
const auto _Old_last = reinterpret_cast<const char*>(_Unfancy_maybe_null(_Old_last_));
|
||||
const auto _New_last = reinterpret_cast<const char*>(_Unfancy_maybe_null(_New_last_));
|
||||
if constexpr (_Has_minimum_allocation_alignment<vector>) {
|
||||
__sanitizer_annotate_contiguous_container(_First, _End, _Old_last, _New_last);
|
||||
} else {
|
||||
const void* const _Aligned_first = _Get_aligned_first(_First, _End);
|
||||
if (!_Aligned_first) {
|
||||
// There is no aligned address within the underlying buffer; nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
const void* const _Aligned_old_last = _Old_last < _Aligned_first ? _Aligned_first : _Old_last;
|
||||
const void* const _Aligned_new_last = _New_last < _Aligned_first ? _Aligned_first : _New_last;
|
||||
const void* const _Aligned_end = _End < _Aligned_first ? _Aligned_first : _End;
|
||||
__sanitizer_annotate_contiguous_container(
|
||||
_Aligned_first, _Aligned_end, _Aligned_old_last, _Aligned_new_last);
|
||||
}
|
||||
}
|
||||
|
||||
class _NODISCARD _Asan_extend_guard {
|
||||
public:
|
||||
_Asan_extend_guard(const _Asan_extend_guard&) = delete;
|
||||
_Asan_extend_guard& operator=(const _Asan_extend_guard&) = delete;
|
||||
|
||||
constexpr explicit _Asan_extend_guard(vector* _Myvec_, size_type _Target_size_) noexcept
|
||||
: _Myvec(_Myvec_), _Target_size(_Target_size_) {
|
||||
_STL_INTERNAL_CHECK(_Myvec != nullptr);
|
||||
auto& _My_data = _Myvec->_Mypair._Myval2;
|
||||
_Apply_annotation(_My_data._Myfirst, _My_data._Myend, _My_data._Mylast, _My_data._Myfirst + _Target_size);
|
||||
}
|
||||
|
||||
_CONSTEXPR20 ~_Asan_extend_guard() {
|
||||
if (!_Myvec) { // Operation succeeded, no modification to the shadow memory required.
|
||||
return;
|
||||
}
|
||||
|
||||
// Shrinks the shadow memory to the current size of the vector.
|
||||
auto& _My_data = _Myvec->_Mypair._Myval2;
|
||||
_Apply_annotation(_My_data._Myfirst, _My_data._Myend, _My_data._Myfirst + _Target_size, _My_data._Mylast);
|
||||
}
|
||||
|
||||
_CONSTEXPR20 void _Release() noexcept {
|
||||
_Myvec = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
vector* _Myvec;
|
||||
size_type _Target_size;
|
||||
};
|
||||
|
||||
class _NODISCARD _Asan_create_guard {
|
||||
public:
|
||||
_Asan_create_guard(const _Asan_create_guard&) = delete;
|
||||
_Asan_create_guard& operator=(const _Asan_create_guard&) = delete;
|
||||
|
||||
constexpr explicit _Asan_create_guard(const vector& _Myvec_) noexcept : _Myvec(_Myvec_) {}
|
||||
|
||||
_CONSTEXPR20 ~_Asan_create_guard() {
|
||||
_Myvec._Create_annotation();
|
||||
}
|
||||
|
||||
private:
|
||||
const vector& _Myvec;
|
||||
};
|
||||
|
||||
#define _ASAN_VECTOR_MODIFY(n) _Modify_annotation((n))
|
||||
#define _ASAN_VECTOR_REMOVE _Remove_annotation()
|
||||
#define _ASAN_VECTOR_CREATE _Create_annotation()
|
||||
#define _ASAN_VECTOR_CREATE_GUARD _Asan_create_guard _Annotator(*this)
|
||||
#define _ASAN_VECTOR_EXTEND_GUARD(n) _Asan_extend_guard _Annotator(this, (n))
|
||||
#define _ASAN_VECTOR_RELEASE_GUARD _Annotator._Release()
|
||||
#else // ^^^ _INSERT_VECTOR_ANNOTATION ^^^ // vvv !_INSERT_VECTOR_ANNOTATION vvv
|
||||
#define _ASAN_VECTOR_MODIFY(n)
|
||||
#define _ASAN_VECTOR_REMOVE
|
||||
#define _ASAN_VECTOR_CREATE
|
||||
#define _ASAN_VECTOR_CREATE_GUARD
|
||||
#define _ASAN_VECTOR_EXTEND_GUARD(n)
|
||||
#define _ASAN_VECTOR_RELEASE_GUARD
|
||||
#endif // !_INSERT_VECTOR_ANNOTATION
|
||||
|
||||
using _Scary_val = _Vector_val<conditional_t<_Is_simple_alloc_v<_Alty>, _Simple_types<_Ty>,
|
||||
_Vec_iter_types<_Ty, size_type, difference_type, pointer, const_pointer, _Ty&, const _Ty&>>>;
|
||||
|
||||
|
@ -494,7 +678,8 @@ public:
|
|||
_Tidy_guard<vector> _Guard{this};
|
||||
|
||||
for (; _UFirst != _ULast; ++_UFirst) {
|
||||
emplace_back(*_UFirst); // performance note: emplace_back()'s strong guarantee is unnecessary here
|
||||
// performance note: _Emplace_one_at_back's strong guarantee is unnecessary here.
|
||||
_Emplace_one_at_back(*_UFirst);
|
||||
}
|
||||
|
||||
_Guard._Target = nullptr;
|
||||
|
@ -547,6 +732,8 @@ public:
|
|||
_Tidy_guard<vector> _Guard{this};
|
||||
_My_data._Mylast =
|
||||
_Uninitialized_move(_Right_data._Myfirst, _Right_data._Mylast, _My_data._Myfirst, _Al);
|
||||
|
||||
_ASAN_VECTOR_CREATE;
|
||||
_Guard._Target = nullptr;
|
||||
}
|
||||
_Proxy._Release();
|
||||
|
@ -599,47 +786,39 @@ public:
|
|||
|
||||
private:
|
||||
template <class... _Valty>
|
||||
_CONSTEXPR20 decltype(auto) _Emplace_back_with_unused_capacity(_Valty&&... _Val) {
|
||||
_CONSTEXPR20 _Ty& _Emplace_one_at_back(_Valty&&... _Val) {
|
||||
// insert by perfectly forwarding into element at end, provide strong guarantee
|
||||
auto& _My_data = _Mypair._Myval2;
|
||||
pointer& _Mylast = _My_data._Mylast;
|
||||
_STL_INTERNAL_CHECK(_Mylast != _My_data._Myend); // check that we have unused capacity
|
||||
_Alty_traits::construct(_Getal(), _Unfancy(_Mylast), _STD forward<_Valty>(_Val)...);
|
||||
_Orphan_range(_Mylast, _Mylast);
|
||||
_Ty& _Result = *_Mylast;
|
||||
++_Mylast;
|
||||
#if _HAS_CXX17
|
||||
return _Result;
|
||||
#else // ^^^ _HAS_CXX17 ^^^ // vvv !_HAS_CXX17 vvv
|
||||
(void) _Result;
|
||||
#endif // _HAS_CXX17
|
||||
}
|
||||
|
||||
public:
|
||||
template <class... _Valty>
|
||||
_CONSTEXPR20 decltype(auto) emplace_back(_Valty&&... _Val) {
|
||||
// insert by perfectly forwarding into element at end, provide strong guarantee
|
||||
auto& _My_data = _Mypair._Myval2;
|
||||
pointer& _Mylast = _My_data._Mylast;
|
||||
if (_Mylast != _My_data._Myend) {
|
||||
return _Emplace_back_with_unused_capacity(_STD forward<_Valty>(_Val)...);
|
||||
}
|
||||
|
||||
_Ty& _Result = *_Emplace_reallocate(_Mylast, _STD forward<_Valty>(_Val)...);
|
||||
#if _HAS_CXX17
|
||||
return *_Emplace_reallocate(_Mylast, _STD forward<_Valty>(_Val)...);
|
||||
}
|
||||
|
||||
template <class... _Valty>
|
||||
_CONSTEXPR20 _Ty& _Emplace_back_with_unused_capacity(_Valty&&... _Val) {
|
||||
// insert by perfectly forwarding into element at end, provide strong guarantee
|
||||
auto& _My_data = _Mypair._Myval2;
|
||||
pointer& _Mylast = _My_data._Mylast;
|
||||
_STL_INTERNAL_CHECK(_Mylast != _My_data._Myend); // check that we have unused capacity
|
||||
if constexpr (conjunction_v<is_nothrow_constructible<_Ty, _Valty...>,
|
||||
_Uses_default_construct<_Alloc, _Ty*, _Valty...>>) {
|
||||
_ASAN_VECTOR_MODIFY(1);
|
||||
_Construct_in_place(*_Mylast, _STD forward<_Valty>(_Val)...);
|
||||
} else {
|
||||
_ASAN_VECTOR_EXTEND_GUARD(static_cast<size_type>(_Mylast - _My_data._Myfirst) + 1);
|
||||
_Alty_traits::construct(_Getal(), _Unfancy(_Mylast), _STD forward<_Valty>(_Val)...);
|
||||
_ASAN_VECTOR_RELEASE_GUARD;
|
||||
}
|
||||
|
||||
_Orphan_range(_Mylast, _Mylast);
|
||||
_Ty& _Result = *_Mylast;
|
||||
++_Mylast;
|
||||
|
||||
return _Result;
|
||||
#else // ^^^ _HAS_CXX17 ^^^ // vvv !_HAS_CXX17 vvv
|
||||
(void) _Result;
|
||||
#endif // _HAS_CXX17
|
||||
}
|
||||
|
||||
_CONSTEXPR20 void push_back(const _Ty& _Val) { // insert element at end, provide strong guarantee
|
||||
emplace_back(_Val);
|
||||
}
|
||||
|
||||
_CONSTEXPR20 void push_back(_Ty&& _Val) {
|
||||
// insert by moving into element at end, provide strong guarantee
|
||||
emplace_back(_STD move(_Val));
|
||||
}
|
||||
|
||||
template <class... _Valty>
|
||||
|
@ -691,6 +870,27 @@ public:
|
|||
return _Newvec + _Whereoff;
|
||||
}
|
||||
|
||||
public:
|
||||
template <class... _Valty>
|
||||
_CONSTEXPR20 decltype(auto) emplace_back(_Valty&&... _Val) {
|
||||
// insert by perfectly forwarding into element at end, provide strong guarantee
|
||||
_Ty& _Result = _Emplace_one_at_back(_STD forward<_Valty>(_Val)...);
|
||||
#if _HAS_CXX17
|
||||
return _Result;
|
||||
#else // ^^^ _HAS_CXX17 ^^^ // vvv !_HAS_CXX17 vvv
|
||||
(void) _Result;
|
||||
#endif // _HAS_CXX17
|
||||
}
|
||||
|
||||
_CONSTEXPR20 void push_back(const _Ty& _Val) { // insert element at end, provide strong guarantee
|
||||
emplace_back(_Val);
|
||||
}
|
||||
|
||||
_CONSTEXPR20 void push_back(_Ty&& _Val) {
|
||||
// insert by moving into element at end, provide strong guarantee
|
||||
emplace_back(_STD move(_Val));
|
||||
}
|
||||
|
||||
template <class... _Valty>
|
||||
_CONSTEXPR20 iterator emplace(const_iterator _Where, _Valty&&... _Val) {
|
||||
// insert by perfectly forwarding _Val at _Where
|
||||
|
@ -711,7 +911,9 @@ public:
|
|||
_Alloc_temporary2<_Alty> _Obj(_Al, _STD forward<_Valty>(_Val)...); // handle aliasing
|
||||
// after constructing _Obj, provide basic guarantee
|
||||
_Orphan_range(_Whereptr, _Oldlast);
|
||||
_ASAN_VECTOR_EXTEND_GUARD(static_cast<size_type>(_Oldlast - _My_data._Myfirst) + 1);
|
||||
_Alty_traits::construct(_Al, _Unfancy(_Oldlast), _STD move(_Oldlast[-1]));
|
||||
_ASAN_VECTOR_RELEASE_GUARD;
|
||||
++_My_data._Mylast;
|
||||
_Move_backward_unchecked(_Whereptr, _Oldlast - 1, _Oldlast);
|
||||
*_Whereptr = _STD move(_Obj._Get_value());
|
||||
|
@ -794,6 +996,7 @@ public:
|
|||
const auto _Affected_elements = static_cast<size_type>(_Oldlast - _Whereptr);
|
||||
_Orphan_range(_Whereptr, _Oldlast);
|
||||
|
||||
_ASAN_VECTOR_EXTEND_GUARD(static_cast<size_type>(_Oldlast - _My_data._Myfirst) + _Count);
|
||||
if (_Count > _Affected_elements) { // new stuff spills off end
|
||||
_Mylast = _Uninitialized_fill_n(_Oldlast, _Count - _Affected_elements, _Tmp, _Al);
|
||||
_Mylast = _Uninitialized_move(_Whereptr, _Oldlast, _Mylast, _Al);
|
||||
|
@ -803,6 +1006,7 @@ public:
|
|||
_Move_backward_unchecked(_Whereptr, _Oldlast - _Count, _Oldlast);
|
||||
_STD fill(_Whereptr, _Whereptr + _Count, _Tmp);
|
||||
}
|
||||
_ASAN_VECTOR_RELEASE_GUARD;
|
||||
}
|
||||
|
||||
return _Make_iterator_offset(_Whereoff);
|
||||
|
@ -824,10 +1028,10 @@ private:
|
|||
|
||||
// For one-at-back, provide strong guarantee.
|
||||
// Otherwise, provide basic guarantee (despite N4659 26.3.11.5 [vector.modifiers]/1).
|
||||
// Performance note: except for one-at-back, emplace_back()'s strong guarantee is unnecessary here.
|
||||
// Performance note: except for one-at-back, _Emplace_one_at_back()'s strong guarantee is unnecessary here.
|
||||
|
||||
for (; _First != _Last; ++_First) {
|
||||
emplace_back(*_First);
|
||||
_Emplace_one_at_back(*_First);
|
||||
}
|
||||
|
||||
_Orphan_range(_Myfirst + _Whereoff, _Myfirst + _Oldsize);
|
||||
|
@ -893,6 +1097,7 @@ private:
|
|||
|
||||
const auto _Affected_elements = static_cast<size_type>(_Oldlast - _Whereptr);
|
||||
|
||||
_ASAN_VECTOR_EXTEND_GUARD(static_cast<size_type>(_Oldlast - _Oldfirst) + _Count);
|
||||
if (_Count < _Affected_elements) { // some affected elements must be assigned
|
||||
_Mylast = _Uninitialized_move(_Oldlast - _Count, _Oldlast, _Oldlast, _Al);
|
||||
_Move_backward_unchecked(_Whereptr, _Oldlast - _Count, _Oldlast);
|
||||
|
@ -945,6 +1150,7 @@ private:
|
|||
}
|
||||
|
||||
_Orphan_range(_Whereptr, _Oldlast);
|
||||
_ASAN_VECTOR_RELEASE_GUARD;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -977,22 +1183,40 @@ public:
|
|||
pointer& _Myfirst = _My_data._Myfirst;
|
||||
pointer& _Mylast = _My_data._Mylast;
|
||||
|
||||
constexpr bool _Nothrow_construct =
|
||||
conjunction_v<is_nothrow_copy_constructible<_Ty>, _Uses_default_construct<_Alloc, _Ty*, const _Ty&>>;
|
||||
|
||||
_My_data._Orphan_all();
|
||||
const auto _Oldcapacity = static_cast<size_type>(_My_data._Myend - _Myfirst);
|
||||
if (_Newsize > _Oldcapacity) { // reallocate
|
||||
_Clear_and_reserve_geometric(_Newsize);
|
||||
_Mylast = _Uninitialized_fill_n(_Myfirst, _Newsize, _Val, _Al);
|
||||
if constexpr (_Nothrow_construct) {
|
||||
_Mylast = _Uninitialized_fill_n(_Myfirst, _Newsize, _Val, _Al);
|
||||
_ASAN_VECTOR_CREATE;
|
||||
} else {
|
||||
_ASAN_VECTOR_CREATE_GUARD;
|
||||
_Mylast = _Uninitialized_fill_n(_Myfirst, _Newsize, _Val, _Al);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const auto _Oldsize = static_cast<size_type>(_Mylast - _Myfirst);
|
||||
if (_Newsize > _Oldsize) {
|
||||
_STD fill(_Myfirst, _Mylast, _Val);
|
||||
_Mylast = _Uninitialized_fill_n(_Mylast, _Newsize - _Oldsize, _Val, _Al);
|
||||
if constexpr (_Nothrow_construct) {
|
||||
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Newsize - _Oldsize));
|
||||
_Mylast = _Uninitialized_fill_n(_Mylast, _Newsize - _Oldsize, _Val, _Al);
|
||||
} else {
|
||||
_ASAN_VECTOR_EXTEND_GUARD(static_cast<difference_type>(_Newsize - _Oldsize));
|
||||
_Mylast = _Uninitialized_fill_n(_Mylast, _Newsize - _Oldsize, _Val, _Al);
|
||||
_ASAN_VECTOR_RELEASE_GUARD;
|
||||
}
|
||||
} else {
|
||||
const pointer _Newlast = _Myfirst + _Newsize;
|
||||
_STD fill(_Myfirst, _Newlast, _Val);
|
||||
_Destroy_range(_Newlast, _Mylast, _Al);
|
||||
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Newsize - _Oldsize));
|
||||
_Mylast = _Newlast;
|
||||
}
|
||||
}
|
||||
|
@ -1008,7 +1232,6 @@ private:
|
|||
_My_data._Orphan_all();
|
||||
|
||||
pointer _Next = _Myfirst;
|
||||
|
||||
for (; _First != _Last && _Next != _Mylast; ++_First, (void) ++_Next) {
|
||||
*_Next = *_First;
|
||||
}
|
||||
|
@ -1020,11 +1243,13 @@ private:
|
|||
|
||||
// Trim.
|
||||
_Destroy_range(_Next, _Mylast, _Getal());
|
||||
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Next - _Mylast));
|
||||
_Mylast = _Next;
|
||||
|
||||
// Append.
|
||||
for (; _First != _Last; ++_First) {
|
||||
emplace_back(*_First); // performance note: emplace_back()'s strong guarantee is unnecessary here
|
||||
// performance note: _Emplace_one_at_back()'s strong guarantee is unnecessary here
|
||||
_Emplace_one_at_back(*_First);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1038,11 +1263,20 @@ private:
|
|||
pointer& _Mylast = _My_data._Mylast;
|
||||
pointer& _Myend = _My_data._Myend;
|
||||
|
||||
constexpr bool _Nothrow_construct = conjunction_v<is_nothrow_constructible<_Ty, _Iter_ref_t<_Iter>>,
|
||||
_Uses_default_construct<_Alloc, _Ty*, _Iter_ref_t<_Iter>>>;
|
||||
|
||||
_My_data._Orphan_all();
|
||||
const auto _Oldcapacity = static_cast<size_type>(_Myend - _Myfirst);
|
||||
if (_Newsize > _Oldcapacity) {
|
||||
_Clear_and_reserve_geometric(_Newsize);
|
||||
_Mylast = _Uninitialized_copy(_First, _Last, _Myfirst, _Al);
|
||||
if constexpr (_Nothrow_construct) {
|
||||
_Mylast = _Uninitialized_copy(_First, _Last, _Myfirst, _Al);
|
||||
_ASAN_VECTOR_CREATE;
|
||||
} else {
|
||||
_ASAN_VECTOR_CREATE_GUARD;
|
||||
_Mylast = _Uninitialized_copy(_First, _Last, _Myfirst, _Al);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1051,11 +1285,20 @@ private:
|
|||
// performance note: traversing [_First, _Mid) twice
|
||||
const _Iter _Mid = _STD next(_First, static_cast<difference_type>(_Oldsize));
|
||||
_Copy_unchecked(_First, _Mid, _Myfirst);
|
||||
_Mylast = _Uninitialized_copy(_Mid, _Last, _Mylast, _Al);
|
||||
|
||||
if constexpr (_Nothrow_construct) {
|
||||
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Newsize - _Oldsize));
|
||||
_Mylast = _Uninitialized_copy(_Mid, _Last, _Mylast, _Al);
|
||||
} else {
|
||||
_ASAN_VECTOR_EXTEND_GUARD(static_cast<difference_type>(_Newsize - _Oldsize));
|
||||
_Mylast = _Uninitialized_copy(_Mid, _Last, _Mylast, _Al);
|
||||
_ASAN_VECTOR_RELEASE_GUARD;
|
||||
}
|
||||
} else {
|
||||
const pointer _Newlast = _Myfirst + _Newsize;
|
||||
_Copy_unchecked(_First, _Last, _Myfirst);
|
||||
_Destroy_range(_Newlast, _Mylast, _Al);
|
||||
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Newsize - _Oldsize));
|
||||
_Mylast = _Newlast;
|
||||
}
|
||||
}
|
||||
|
@ -1151,6 +1394,7 @@ private:
|
|||
const pointer _Newlast = _Myfirst + _Newsize;
|
||||
_Orphan_range(_Newlast, _Mylast);
|
||||
_Destroy_range(_Newlast, _Mylast, _Al);
|
||||
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Newsize - _Oldsize));
|
||||
_Mylast = _Newlast;
|
||||
return;
|
||||
}
|
||||
|
@ -1162,6 +1406,7 @@ private:
|
|||
return;
|
||||
}
|
||||
|
||||
_ASAN_VECTOR_EXTEND_GUARD(_Newsize - _Oldsize);
|
||||
const pointer _Oldlast = _Mylast;
|
||||
if constexpr (is_same_v<_Ty2, _Ty>) {
|
||||
_Mylast = _Uninitialized_fill_n(_Oldlast, _Newsize - _Oldsize, _Val, _Al);
|
||||
|
@ -1169,6 +1414,7 @@ private:
|
|||
_STL_INTERNAL_STATIC_ASSERT(is_same_v<_Ty2, _Value_init_tag>);
|
||||
_Mylast = _Uninitialized_value_construct_n(_Oldlast, _Newsize - _Oldsize, _Al);
|
||||
}
|
||||
_ASAN_VECTOR_RELEASE_GUARD;
|
||||
_Orphan_range(_Oldlast, _Oldlast);
|
||||
}
|
||||
|
||||
|
@ -1252,6 +1498,7 @@ private:
|
|||
|
||||
if (_Myfirst) { // destroy and deallocate old array
|
||||
_Destroy_range(_Myfirst, _Mylast, _Al);
|
||||
_ASAN_VECTOR_REMOVE;
|
||||
_Al.deallocate(_Myfirst, static_cast<size_type>(_Myend - _Myfirst));
|
||||
|
||||
_Myfirst = nullptr;
|
||||
|
@ -1297,6 +1544,7 @@ public:
|
|||
|
||||
_Orphan_range(_Mylast - 1, _Mylast);
|
||||
_Alty_traits::destroy(_Getal(), _Unfancy(_Mylast - 1));
|
||||
_ASAN_VECTOR_MODIFY(-1);
|
||||
--_Mylast;
|
||||
}
|
||||
|
||||
|
@ -1315,6 +1563,7 @@ public:
|
|||
_Orphan_range(_Whereptr, _Mylast);
|
||||
_Move_unchecked(_Whereptr + 1, _Mylast, _Whereptr);
|
||||
_Alty_traits::destroy(_Getal(), _Unfancy(_Mylast - 1));
|
||||
_ASAN_VECTOR_MODIFY(-1);
|
||||
--_Mylast;
|
||||
return iterator(_Whereptr, _STD addressof(_My_data));
|
||||
}
|
||||
|
@ -1337,6 +1586,7 @@ public:
|
|||
|
||||
const pointer _Newlast = _Move_unchecked(_Lastptr, _Mylast, _Firstptr);
|
||||
_Destroy_range(_Newlast, _Mylast, _Getal());
|
||||
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Newlast - _Mylast));
|
||||
_Mylast = _Newlast;
|
||||
}
|
||||
|
||||
|
@ -1350,6 +1600,7 @@ public:
|
|||
|
||||
_My_data._Orphan_all();
|
||||
_Destroy_range(_Myfirst, _Mylast, _Getal());
|
||||
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Mylast - _Myfirst));
|
||||
_Mylast = _Myfirst;
|
||||
}
|
||||
|
||||
|
@ -1599,12 +1850,14 @@ private:
|
|||
|
||||
if (_Myfirst) { // destroy and deallocate old array
|
||||
_Destroy_range(_Myfirst, _Mylast, _Al);
|
||||
_ASAN_VECTOR_REMOVE;
|
||||
_Al.deallocate(_Myfirst, static_cast<size_type>(_Myend - _Myfirst));
|
||||
}
|
||||
|
||||
_Myfirst = _Newvec;
|
||||
_Mylast = _Newvec + _Newsize;
|
||||
_Myend = _Newvec + _Newcapacity;
|
||||
_ASAN_VECTOR_CREATE;
|
||||
}
|
||||
|
||||
_CONSTEXPR20 void _Tidy() noexcept { // free all storage
|
||||
|
@ -1618,6 +1871,7 @@ private:
|
|||
|
||||
if (_Myfirst) { // destroy and deallocate old array
|
||||
_Destroy_range(_Myfirst, _Mylast, _Al);
|
||||
_ASAN_VECTOR_REMOVE;
|
||||
_Al.deallocate(_Myfirst, static_cast<size_type>(_Myend - _Myfirst));
|
||||
|
||||
_Myfirst = nullptr;
|
||||
|
@ -1649,6 +1903,7 @@ private:
|
|||
} else {
|
||||
static_assert(_Always_false<_Ty>, "Should be unreachable");
|
||||
}
|
||||
_ASAN_VECTOR_CREATE;
|
||||
_Guard._Target = nullptr;
|
||||
}
|
||||
|
||||
|
@ -1667,11 +1922,20 @@ private:
|
|||
pointer& _Myfirst = _My_data._Myfirst;
|
||||
pointer& _Mylast = _My_data._Mylast;
|
||||
|
||||
constexpr bool _Nothrow_construct =
|
||||
conjunction_v<is_nothrow_move_constructible<_Ty>, _Uses_default_construct<_Alloc, _Ty*, _Ty>>;
|
||||
|
||||
_My_data._Orphan_all();
|
||||
const auto _Oldcapacity = static_cast<size_type>(_My_data._Myend - _Myfirst);
|
||||
if (_Newsize > _Oldcapacity) {
|
||||
_Clear_and_reserve_geometric(_Newsize);
|
||||
_Mylast = _Uninitialized_move(_First, _Last, _Myfirst, _Al);
|
||||
if constexpr (_Nothrow_construct) {
|
||||
_Mylast = _Uninitialized_move(_First, _Last, _Myfirst, _Al);
|
||||
_ASAN_VECTOR_CREATE;
|
||||
} else {
|
||||
_ASAN_VECTOR_CREATE_GUARD;
|
||||
_Mylast = _Uninitialized_move(_First, _Last, _Myfirst, _Al);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1679,11 +1943,20 @@ private:
|
|||
if (_Newsize > _Oldsize) {
|
||||
const pointer _Mid = _First + _Oldsize;
|
||||
_Move_unchecked(_First, _Mid, _Myfirst);
|
||||
_Mylast = _Uninitialized_move(_Mid, _Last, _Mylast, _Al);
|
||||
|
||||
if constexpr (_Nothrow_construct) {
|
||||
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Newsize - _Oldsize));
|
||||
_Mylast = _Uninitialized_move(_Mid, _Last, _Mylast, _Al);
|
||||
} else {
|
||||
_ASAN_VECTOR_EXTEND_GUARD(_Newsize - _Oldsize);
|
||||
_Mylast = _Uninitialized_move(_Mid, _Last, _Mylast, _Al);
|
||||
_ASAN_VECTOR_RELEASE_GUARD;
|
||||
}
|
||||
} else {
|
||||
const pointer _Newlast = _Myfirst + _Newsize;
|
||||
_Move_unchecked(_First, _Last, _Myfirst);
|
||||
_Destroy_range(_Newlast, _Mylast, _Al);
|
||||
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Newsize - _Oldsize));
|
||||
_Mylast = _Newlast;
|
||||
}
|
||||
}
|
||||
|
@ -3150,6 +3423,15 @@ _NODISCARD _CONSTEXPR20 _Iter_diff_t<_VbIt> _Count_vbool(_VbIt _First, const _Vb
|
|||
return _Count;
|
||||
});
|
||||
}
|
||||
|
||||
#undef _ASAN_VECTOR_MODIFY
|
||||
#undef _ASAN_VECTOR_REMOVE
|
||||
#undef _ASAN_VECTOR_CREATE
|
||||
#undef _ASAN_VECTOR_CREATE_GUARD
|
||||
#undef _ASAN_VECTOR_EXTEND_GUARD
|
||||
#undef _ASAN_VECTOR_RELEASE_GUARD
|
||||
#undef _ACTIVATE_VECTOR_ANNOTATION
|
||||
#undef _INSERT_VECTOR_ANNOTATION
|
||||
_STD_END
|
||||
|
||||
#pragma pop_macro("new")
|
||||
|
|
|
@ -774,6 +774,9 @@ _NODISCARD constexpr allocation_result<typename allocator_traits<_Alloc>::pointe
|
|||
#endif // __cpp_lib_concepts
|
||||
#endif // _HAS_CXX23
|
||||
|
||||
// The number of user bytes a single byte of ASAN shadow memory can track.
|
||||
_INLINE_VAR constexpr size_t _Asan_granularity = 8;
|
||||
|
||||
template <class _Ty>
|
||||
class allocator {
|
||||
public:
|
||||
|
@ -857,6 +860,8 @@ public:
|
|||
return static_cast<size_t>(-1) / sizeof(_Ty);
|
||||
}
|
||||
#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
||||
|
||||
static constexpr size_t _Minimum_allocation_alignment = _Asan_granularity;
|
||||
};
|
||||
|
||||
template <>
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation.
|
||||
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
-->
|
||||
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\..\..\..\crt-common.settings.targets" />
|
||||
|
||||
<ItemGroup Condition="'$(BuildExePhase)' == '1'">
|
||||
<ProjectFile Include="stl_asan.nativeproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="Dogfood">
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation.
|
||||
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
-->
|
||||
|
||||
<ItemGroup>
|
||||
<BuildFiles Include="
|
||||
$(CrtRoot)\github\stl\src\asan.cpp;
|
||||
">
|
||||
<BuildAs>nativecpp</BuildAs>
|
||||
</BuildFiles>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="Dogfood">
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation.
|
||||
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
-->
|
||||
|
||||
<PropertyGroup>
|
||||
<Arm64X>true</Arm64X>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(MSBuildThisFileDirectory)stl_asan.settings.targets"/>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="Dogfood">
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation.
|
||||
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
-->
|
||||
|
||||
<PropertyGroup>
|
||||
<FinalBinary>p_stl_asan</FinalBinary>
|
||||
<TargetType>LIBRARY</TargetType>
|
||||
<Arm64CombinedPdb>true</Arm64CombinedPdb>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\..\..\..\crt_build.settings.targets"/>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputName>stl_asan</OutputName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ClProgramDataBaseFileName>$(OutputLibPdbPath)$(OutputName)$(PdbVerName).pdb</ClProgramDataBaseFileName>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(MSBuildThisFileDirectory)stl_asan.files.settings.targets"/>
|
||||
|
||||
<Import Project="$(VCToolsRootPath)\crt\crt_build.targets"/>
|
||||
<Target Name="GetBaseAddress"/>
|
||||
|
||||
</Project>
|
|
@ -27,7 +27,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|||
<PropertyGroup>
|
||||
<ClProgramDataBaseFileName>$(OutputLibPdbPath)$(OutputName)$(PdbVerName).pdb</ClProgramDataBaseFileName>
|
||||
<ClDefines Condition="'$(DependsOnConcRT)' == 'true'">$(ClDefines);_STL_CONCRT_SUPPORT</ClDefines>
|
||||
<ClDefines>$(ClDefines);_VCRT_ALLOW_INTERNALS</ClDefines>
|
||||
<ClDefines>$(ClDefines);_VCRT_ALLOW_INTERNALS;_ANNOTATE_VECTOR</ClDefines>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(MSBuildThisFileDirectory)\stl.files.settings.targets"/>
|
||||
|
|
|
@ -160,6 +160,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|||
<!-- Objs that exist in both libcpmt[d][01].lib and msvcprt[d].lib
|
||||
(controlled by IncludeInLink and IncludeInImportLib). -->
|
||||
<BuildFiles Include="
|
||||
$(CrtRoot)\github\stl\src\asan_noop.cpp;
|
||||
$(CrtRoot)\github\stl\src\filesystem.cpp;
|
||||
$(CrtRoot)\github\stl\src\format.cpp;
|
||||
$(CrtRoot)\github\stl\src\locale0_implib.cpp;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
namespace std {
|
||||
extern "C" {
|
||||
extern const bool _Asan_vector_should_annotate = true;
|
||||
}
|
||||
} // namespace std
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
extern "C" {
|
||||
extern const bool _Asan_vector_should_annotate_default = false;
|
||||
|
||||
void __cdecl __sanitizer_annotate_contiguous_container_default(
|
||||
const void*, const void*, const void*, const void*) noexcept {}
|
||||
}
|
|
@ -186,6 +186,7 @@ tests\GH_001638_dllexport_derived_classes
|
|||
tests\GH_001850_clog_tied_to_cout
|
||||
tests\GH_001858_iostream_exception
|
||||
tests\GH_001914_cached_position
|
||||
tests\GH_002030_asan_annotate_vector
|
||||
tests\GH_002039_byte_is_not_trivially_swappable
|
||||
tests\GH_002058_debug_iterator_race
|
||||
tests\GH_002120_streambuf_seekpos_and_seekoff
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
# This test matrix is the usual test matrix, with all currently unsupported options removed, crossed with the ASan flags.
|
||||
# TRANSITION, VSO-1350252
|
||||
# Due to a bug in the ASan libs using ASan with /MD or /MT requires IDL==0 and using /MDd or /MTd requires IDL==2.
|
||||
# clang-cl does not currently support targeting /MDd or /MTd.
|
||||
RUNALL_INCLUDE ..\prefix.lst
|
||||
RUNALL_CROSSLIST
|
||||
PM_CL="/Zi /wd4611 /w14640 /Zc:threadSafeInit-" PM_LINK="/debug"
|
||||
RUNALL_CROSSLIST
|
||||
PM_CL="-fsanitize=address /BE /c /EHsc /MD /std:c++14 /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /BE /c /EHsc /MDd /std:c++17 /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /BE /c /EHsc /MT /std:c++20 /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /BE /c /EHsc /MTd /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MD /std:c++14 /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MD /std:c++17 /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MD /std:c++20 /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MD /std:c++latest /permissive- /Zc:char8_t- /Zc:preprocessor /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MD /std:c++latest /permissive- /Zc:noexceptTypes- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MDd /std:c++14 /fp:except /Zc:preprocessor /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MDd /std:c++17 /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MDd /std:c++20 /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MDd /std:c++latest /permissive- /Zc:wchar_t- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MDd /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MT /std:c++latest /permissive- /analyze:only /analyze:autolog- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MT /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MTd /std:c++latest /permissive /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MTd /std:c++latest /permissive- /analyze:only /analyze:autolog- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MTd /std:c++latest /permissive- /fp:strict /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /EHsc /MTd /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /Za /EHsc /MD /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="-fsanitize=address /Za /EHsc /MDd /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /BE /c /EHsc /MD /std:c++14 /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /BE /c /EHsc /MDd /std:c++17 /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /BE /c /EHsc /MT /std:c++20 /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /BE /c /EHsc /MTd /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MD /std:c++14 /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MD /std:c++17 /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MD /std:c++20 /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MD /std:c++latest /permissive- /Zc:char8_t- /Zc:preprocessor /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MD /std:c++latest /permissive- /Zc:noexceptTypes- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MDd /std:c++14 /fp:except /Zc:preprocessor /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MDd /std:c++17 /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MDd /std:c++20 /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MDd /std:c++latest /permissive- /Zc:wchar_t- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MDd /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MT /std:c++latest /permissive- /analyze:only /analyze:autolog- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MT /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MTd /std:c++latest /permissive /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MTd /std:c++latest /permissive- /analyze:only /analyze:autolog- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MTd /std:c++latest /permissive- /fp:strict /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /EHsc /MTd /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /Za /EHsc /MD /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
PM_CL="/D_ANNOTATE_VECTOR /Za /EHsc /MDd /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||
# TRANSITION, clang-cl does not support /alternatename so we cannot test /D_ANNOTATE_VECTOR without -fsanitize=address
|
||||
PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing /EHsc /MD /std:c++14"
|
||||
PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing /EHsc /MD /std:c++17"
|
||||
PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing /EHsc /MT /std:c++latest /permissive-"
|
||||
PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing /EHsc /MT /std:c++latest /permissive- /D_HAS_CXX23 /fp:strict"
|
|
@ -0,0 +1,917 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
// REQUIRES: x64 || x86
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifndef __SANITIZE_ADDRESS__
|
||||
#if defined(__clang__) && defined(__has_feature)
|
||||
#if __has_feature(address_sanitizer)
|
||||
#define __SANITIZE_ADDRESS__
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
extern "C" {
|
||||
void* __sanitizer_contiguous_container_find_bad_address(const void* beg, const void* mid, const void* end) noexcept;
|
||||
void __asan_describe_address(void*) noexcept;
|
||||
}
|
||||
#endif // ASan instrumentation enabled
|
||||
|
||||
struct non_trivial_can_throw {
|
||||
non_trivial_can_throw() {}
|
||||
};
|
||||
|
||||
struct non_trivial_cannot_throw {
|
||||
non_trivial_cannot_throw() noexcept {}
|
||||
};
|
||||
|
||||
struct throw_on_construction {
|
||||
throw_on_construction() {
|
||||
throw 0;
|
||||
}
|
||||
|
||||
explicit throw_on_construction(bool should_throw) {
|
||||
if (should_throw) {
|
||||
throw 0;
|
||||
}
|
||||
}
|
||||
|
||||
throw_on_construction(const throw_on_construction&) {
|
||||
throw 0;
|
||||
}
|
||||
|
||||
[[noreturn]] throw_on_construction& operator=(const throw_on_construction&) {
|
||||
throw 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct throw_on_copy {
|
||||
throw_on_copy() = default;
|
||||
|
||||
throw_on_copy(const throw_on_copy&) {
|
||||
throw 0;
|
||||
}
|
||||
|
||||
throw_on_copy(throw_on_copy&&) {}
|
||||
|
||||
[[noreturn]] throw_on_copy& operator=(const throw_on_copy&) {
|
||||
throw 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, int N>
|
||||
class input_iterator_tester {
|
||||
private:
|
||||
T data[N] = {};
|
||||
|
||||
public:
|
||||
class iterator {
|
||||
private:
|
||||
T* curr;
|
||||
|
||||
public:
|
||||
using iterator_category = input_iterator_tag;
|
||||
using value_type = T;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = T&;
|
||||
|
||||
explicit iterator(T* start) : curr(start) {}
|
||||
|
||||
reference operator*() const {
|
||||
return *curr;
|
||||
}
|
||||
|
||||
iterator& operator++() {
|
||||
++curr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) {
|
||||
auto tmp = *this;
|
||||
++curr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const iterator& that) const {
|
||||
return curr == that.curr;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator& that) const {
|
||||
return !(*this == that);
|
||||
}
|
||||
};
|
||||
|
||||
iterator begin() {
|
||||
return iterator(data);
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return iterator(data + N);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class Alloc>
|
||||
bool verify_vector(vector<T, Alloc>& vec) {
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
size_t buffer_bytes = vec.capacity() * sizeof(T);
|
||||
void* buffer = vec.data();
|
||||
void* aligned_start = align(8, 1, buffer, buffer_bytes);
|
||||
|
||||
if (!aligned_start) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void* mid = vec.data() + vec.size();
|
||||
mid = mid > aligned_start ? mid : aligned_start;
|
||||
|
||||
void* bad_address =
|
||||
__sanitizer_contiguous_container_find_bad_address(aligned_start, mid, vec.data() + vec.capacity());
|
||||
if (bad_address == nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bad_address < mid) {
|
||||
cout << bad_address << " was marked as poisoned when it should not be." << endl;
|
||||
} else {
|
||||
cout << bad_address << " was not marked as poisoned when it should be." << endl;
|
||||
}
|
||||
cout << "Vector State:" << endl;
|
||||
cout << " begin: " << buffer << endl;
|
||||
cout << " aligned begin: " << aligned_start << endl;
|
||||
cout << " last: " << reinterpret_cast<void*>(vec.data() + vec.size()) << endl;
|
||||
cout << " end: " << reinterpret_cast<void*>(vec.data() + vec.capacity()) << endl;
|
||||
__asan_describe_address(bad_address);
|
||||
|
||||
return false;
|
||||
#else // ^^^ ASan instrumentation enabled ^^^ // vvv ASan instrumentation disabled vvv
|
||||
(void) vec;
|
||||
return true;
|
||||
#endif // Asan instrumentation disabled
|
||||
}
|
||||
|
||||
// Note: This class does not satisfy all the allocator requirements but is sufficient for this test.
|
||||
template <class T, class Pocma, class Stateless>
|
||||
struct custom_test_allocator {
|
||||
using value_type = T;
|
||||
using propagate_on_container_move_assignment = Pocma;
|
||||
using is_always_equal = Stateless;
|
||||
};
|
||||
|
||||
template <class T1, class T2, class Pocma, class Stateless>
|
||||
constexpr bool operator==(
|
||||
const custom_test_allocator<T1, Pocma, Stateless>&, const custom_test_allocator<T2, Pocma, Stateless>&) noexcept {
|
||||
return Stateless::value;
|
||||
}
|
||||
|
||||
template <class T1, class T2, class Pocma, class Stateless>
|
||||
constexpr bool operator!=(
|
||||
const custom_test_allocator<T1, Pocma, Stateless>&, const custom_test_allocator<T2, Pocma, Stateless>&) noexcept {
|
||||
return !Stateless::value;
|
||||
}
|
||||
|
||||
template <class T, class Pocma = true_type, class Stateless = true_type>
|
||||
struct aligned_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
||||
static constexpr size_t _Minimum_allocation_alignment = 8;
|
||||
|
||||
aligned_allocator() = default;
|
||||
template <class U>
|
||||
constexpr aligned_allocator(const aligned_allocator<U, Pocma, Stateless>&) noexcept {}
|
||||
|
||||
T* allocate(size_t n) {
|
||||
return new T[n];
|
||||
}
|
||||
|
||||
void deallocate(T* p, size_t) noexcept {
|
||||
delete[] p;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class Pocma = true_type, class Stateless = true_type>
|
||||
struct explicit_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
||||
static constexpr size_t _Minimum_allocation_alignment = alignof(T);
|
||||
|
||||
explicit_allocator() = default;
|
||||
template <class U>
|
||||
constexpr explicit_allocator(const explicit_allocator<U, Pocma, Stateless>&) noexcept {}
|
||||
|
||||
T* allocate(size_t n) {
|
||||
T* mem = new T[n + 1];
|
||||
return mem + 1;
|
||||
}
|
||||
|
||||
void deallocate(T* p, size_t) noexcept {
|
||||
delete[](p - 1);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class Pocma = true_type, class Stateless = true_type>
|
||||
struct implicit_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
||||
implicit_allocator() = default;
|
||||
template <class U>
|
||||
constexpr implicit_allocator(const implicit_allocator<U, Pocma, Stateless>&) noexcept {}
|
||||
|
||||
T* allocate(size_t n) {
|
||||
T* mem = new T[n + 1];
|
||||
return mem + 1;
|
||||
}
|
||||
|
||||
void deallocate(T* p, size_t) noexcept {
|
||||
delete[](p - 1);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Alloc>
|
||||
void test_push_pop() {
|
||||
using T = typename Alloc::value_type;
|
||||
|
||||
vector<T, Alloc> v;
|
||||
assert(verify_vector(v));
|
||||
|
||||
v.push_back(T());
|
||||
assert(verify_vector(v));
|
||||
|
||||
v.pop_back();
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
|
||||
template <class Alloc, int Size = 1024, int Stride = 128>
|
||||
void test_reserve_shrink() {
|
||||
using T = typename Alloc::value_type;
|
||||
|
||||
vector<T, Alloc> v;
|
||||
assert(verify_vector(v));
|
||||
|
||||
v.reserve(Size);
|
||||
assert(verify_vector(v));
|
||||
|
||||
for (int i = 0; i < Size; i += Stride) {
|
||||
for (int j = 0; j < Stride && j + i < Size; ++j) {
|
||||
v.push_back(T());
|
||||
}
|
||||
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
|
||||
v.push_back(T());
|
||||
assert(verify_vector(v));
|
||||
|
||||
for (int i = 0; i < Size; i += Stride) {
|
||||
for (int j = 0; j < Stride && j + i < Size; ++j) {
|
||||
v.pop_back();
|
||||
}
|
||||
|
||||
v.shrink_to_fit();
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
|
||||
v.pop_back();
|
||||
assert(verify_vector(v));
|
||||
v.shrink_to_fit();
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
|
||||
template <class Alloc>
|
||||
void test_emplace_pop() {
|
||||
using T = typename Alloc::value_type;
|
||||
|
||||
vector<T, Alloc> v;
|
||||
assert(verify_vector(v));
|
||||
|
||||
v.emplace_back(T());
|
||||
assert(verify_vector(v));
|
||||
|
||||
v.emplace(v.begin(), T());
|
||||
assert(verify_vector(v));
|
||||
|
||||
v.emplace(v.end(), T());
|
||||
assert(verify_vector(v));
|
||||
|
||||
v.pop_back();
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
|
||||
template <class Alloc>
|
||||
void test_move_assign() {
|
||||
using T = typename Alloc::value_type;
|
||||
|
||||
vector<T, Alloc> v1;
|
||||
vector<T, Alloc> v2;
|
||||
assert(verify_vector(v1));
|
||||
assert(verify_vector(v2));
|
||||
|
||||
v1.push_back(T());
|
||||
assert(verify_vector(v1));
|
||||
|
||||
v2 = move(v1);
|
||||
assert(verify_vector(v1));
|
||||
assert(verify_vector(v2));
|
||||
}
|
||||
|
||||
template <class Alloc>
|
||||
void test_copy_assign() {
|
||||
using T = typename Alloc::value_type;
|
||||
|
||||
vector<T, Alloc> v1;
|
||||
vector<T, Alloc> v2;
|
||||
assert(verify_vector(v1));
|
||||
assert(verify_vector(v2));
|
||||
|
||||
v1.push_back(T());
|
||||
assert(verify_vector(v1));
|
||||
|
||||
v2 = v1;
|
||||
assert(verify_vector(v1));
|
||||
assert(verify_vector(v2));
|
||||
}
|
||||
|
||||
template <class Alloc, int N = 128>
|
||||
void test_constructors() {
|
||||
using T = typename Alloc::value_type;
|
||||
Alloc al = Alloc();
|
||||
|
||||
vector<T, Alloc> v1;
|
||||
vector<T, Alloc> v2(al);
|
||||
vector<T, Alloc> v3(N, T());
|
||||
vector<T, Alloc> v4(N);
|
||||
assert(verify_vector(v1));
|
||||
assert(verify_vector(v2));
|
||||
assert(verify_vector(v3));
|
||||
assert(verify_vector(v4));
|
||||
|
||||
vector<T, Alloc> v5(v3.begin(), v3.end());
|
||||
vector<T, Alloc> v6(v3);
|
||||
vector<T, Alloc> v7(v3, al);
|
||||
assert(verify_vector(v5));
|
||||
assert(verify_vector(v6));
|
||||
assert(verify_vector(v7));
|
||||
|
||||
vector<T, Alloc> v8(move(v3));
|
||||
vector<T, Alloc> v9(move(v4), al);
|
||||
assert(verify_vector(v8));
|
||||
assert(verify_vector(v9));
|
||||
|
||||
vector<T, Alloc> v10({T(), T()});
|
||||
assert(verify_vector(v10));
|
||||
}
|
||||
|
||||
template <class Alloc, int N = 128>
|
||||
void test_insert_n() {
|
||||
using T = typename Alloc::value_type;
|
||||
|
||||
vector<T, Alloc> v(1);
|
||||
|
||||
v.insert(v.begin(), N, T());
|
||||
assert(verify_vector(v));
|
||||
v.insert(v.end(), N, T());
|
||||
assert(verify_vector(v));
|
||||
v.insert(v.begin() + N, N, T());
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
|
||||
template <class Alloc, int N = 128>
|
||||
void test_insert_range() {
|
||||
using T = typename Alloc::value_type;
|
||||
|
||||
vector<T, Alloc> v1(1);
|
||||
vector<T, Alloc> v2(N);
|
||||
input_iterator_tester<T, N> t;
|
||||
|
||||
v1.insert(v1.begin(), v2.begin(), v2.end());
|
||||
assert(verify_vector(v1));
|
||||
v1.insert(v1.end(), v2.begin(), v2.end());
|
||||
assert(verify_vector(v1));
|
||||
v1.insert(v1.begin() + N, v2.begin(), v2.end());
|
||||
assert(verify_vector(v1));
|
||||
|
||||
v1.insert(v1.begin(), t.begin(), t.end());
|
||||
assert(verify_vector(v1));
|
||||
v1.insert(v1.end(), t.begin(), t.end());
|
||||
assert(verify_vector(v1));
|
||||
v1.insert(v1.begin() + N, t.begin(), t.end());
|
||||
assert(verify_vector(v1));
|
||||
}
|
||||
|
||||
template <class Alloc, int N = 128>
|
||||
void test_assign() {
|
||||
using T = typename Alloc::value_type;
|
||||
|
||||
vector<T, Alloc> v1(1);
|
||||
vector<T, Alloc> v2(N + 1);
|
||||
vector<T, Alloc> v3(N + 2);
|
||||
input_iterator_tester<T, N + 2> t1;
|
||||
input_iterator_tester<T, N + 3> t2;
|
||||
|
||||
v1.assign(N, T());
|
||||
assert(verify_vector(v1));
|
||||
v1.assign(v2.begin(), v2.end());
|
||||
assert(verify_vector(v1));
|
||||
v1.assign(v3.begin(), v3.end());
|
||||
assert(verify_vector(v1));
|
||||
v1.assign(t1.begin(), t1.end());
|
||||
assert(verify_vector(v1));
|
||||
v1.assign(t2.begin(), t2.end());
|
||||
assert(verify_vector(v1));
|
||||
v1.assign(t1.begin(), t1.end());
|
||||
assert(verify_vector(v1));
|
||||
v1.assign(v3.begin(), v3.end());
|
||||
assert(verify_vector(v1));
|
||||
v1.assign(v2.begin(), v2.end());
|
||||
assert(verify_vector(v1));
|
||||
v1.assign(N, T());
|
||||
assert(verify_vector(v1));
|
||||
|
||||
vector<T, Alloc> v4;
|
||||
v4.assign({T()});
|
||||
assert(verify_vector(v4));
|
||||
v4.assign({T(), T()});
|
||||
assert(verify_vector(v4));
|
||||
v4.assign({T()});
|
||||
assert(verify_vector(v4));
|
||||
}
|
||||
|
||||
template <class Alloc, int N = 128>
|
||||
void test_resize() {
|
||||
using T = typename Alloc::value_type;
|
||||
|
||||
vector<T, Alloc> v;
|
||||
v.resize(N, T());
|
||||
assert(verify_vector(v));
|
||||
v.resize(1, T());
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
|
||||
void test_push_back_throw() {
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
v.reserve(1);
|
||||
|
||||
throw_on_construction t(false);
|
||||
try {
|
||||
v.push_back(t);
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
throw_on_construction t(false);
|
||||
try {
|
||||
v.push_back(t);
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
v.reserve(1);
|
||||
|
||||
try {
|
||||
v.push_back(throw_on_construction(false));
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
try {
|
||||
v.push_back(throw_on_construction(false));
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_emplace_back_throw() {
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
v.reserve(1);
|
||||
|
||||
try {
|
||||
v.emplace_back(true);
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
try {
|
||||
v.emplace_back(true);
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_insert_range_throw() {
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(4);
|
||||
v.emplace_back(false);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.insert(v.begin(), {throw_on_construction(false), throw_on_construction(false)});
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(2);
|
||||
v.emplace_back(false);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.insert(v.begin(), {throw_on_construction(false), throw_on_construction(false)});
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(2);
|
||||
|
||||
try {
|
||||
v.insert(v.end(), {throw_on_construction(false), throw_on_construction(false)});
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
try {
|
||||
v.insert(v.end(), {throw_on_construction(false), throw_on_construction(false)});
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_insert_throw() {
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(3);
|
||||
v.emplace_back(false);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.insert(v.begin(), throw_on_construction(false));
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(2);
|
||||
v.emplace_back(false);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.insert(v.begin(), throw_on_construction(false));
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(1);
|
||||
|
||||
try {
|
||||
v.insert(v.end(), throw_on_construction(false));
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
try {
|
||||
v.insert(v.end(), throw_on_construction(false));
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_emplace_throw() {
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(3);
|
||||
v.emplace_back(false);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.emplace(v.begin(), false);
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(2);
|
||||
v.emplace_back(false);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.emplace(v.begin(), true);
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(1);
|
||||
|
||||
try {
|
||||
v.emplace(v.end(), true);
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
try {
|
||||
v.emplace(v.end(), true);
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_resize_throw() {
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(2);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.resize(2);
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(1);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.resize(2);
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_copy> v;
|
||||
|
||||
v.reserve(2);
|
||||
v.push_back(throw_on_copy());
|
||||
|
||||
try {
|
||||
v.resize(2, throw_on_copy());
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_copy> v;
|
||||
|
||||
v.reserve(1);
|
||||
v.push_back(throw_on_copy());
|
||||
|
||||
try {
|
||||
v.resize(2, throw_on_copy());
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_insert_n_throw() {
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(2);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.insert(v.begin(), 2, throw_on_construction(false));
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(2);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.insert(v.end(), 2, throw_on_construction(false));
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(1);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.insert(v.begin(), 2, throw_on_construction(false));
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_construction> v;
|
||||
|
||||
v.reserve(1);
|
||||
v.emplace_back(false);
|
||||
|
||||
try {
|
||||
v.insert(v.end(), 2, throw_on_construction(false));
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_copy> v;
|
||||
|
||||
v.reserve(2);
|
||||
v.push_back(throw_on_copy());
|
||||
|
||||
try {
|
||||
v.insert(v.begin(), 2, throw_on_copy());
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_copy> v;
|
||||
|
||||
v.reserve(2);
|
||||
v.push_back(throw_on_copy());
|
||||
|
||||
try {
|
||||
v.insert(v.end(), 2, throw_on_copy());
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_copy> v;
|
||||
|
||||
v.reserve(1);
|
||||
v.push_back(throw_on_copy());
|
||||
|
||||
try {
|
||||
v.insert(v.begin(), 2, throw_on_copy());
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
vector<throw_on_copy> v;
|
||||
|
||||
v.reserve(1);
|
||||
v.push_back(throw_on_copy());
|
||||
|
||||
try {
|
||||
v.insert(v.end(), 2, throw_on_copy());
|
||||
assert(false);
|
||||
} catch (int) {
|
||||
assert(verify_vector(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Alloc>
|
||||
void run_tests() {
|
||||
test_push_pop<Alloc>();
|
||||
test_reserve_shrink<Alloc>();
|
||||
test_emplace_pop<Alloc>();
|
||||
test_move_assign<Alloc>();
|
||||
test_copy_assign<Alloc>();
|
||||
test_constructors<Alloc>();
|
||||
test_insert_n<Alloc>();
|
||||
test_insert_range<Alloc>();
|
||||
test_assign<Alloc>();
|
||||
test_resize<Alloc>();
|
||||
}
|
||||
|
||||
template <class T, template <class, class, class> class AllocT>
|
||||
void run_custom_allocator_matrix() {
|
||||
run_tests<AllocT<T, true_type, true_type>>();
|
||||
run_tests<AllocT<T, true_type, false_type>>();
|
||||
run_tests<AllocT<T, false_type, true_type>>();
|
||||
run_tests<AllocT<T, false_type, false_type>>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void run_allocator_matrix() {
|
||||
run_tests<allocator<T>>();
|
||||
run_custom_allocator_matrix<T, aligned_allocator>();
|
||||
run_custom_allocator_matrix<T, explicit_allocator>();
|
||||
run_custom_allocator_matrix<T, implicit_allocator>();
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Do some work even when we aren't instrumented
|
||||
run_allocator_matrix<char>();
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
run_allocator_matrix<int>();
|
||||
run_allocator_matrix<double>();
|
||||
run_allocator_matrix<non_trivial_can_throw>();
|
||||
run_allocator_matrix<non_trivial_cannot_throw>();
|
||||
|
||||
// TRANSITION, LLVM-35365
|
||||
#ifndef __clang__
|
||||
test_push_back_throw();
|
||||
test_emplace_back_throw();
|
||||
test_insert_range_throw();
|
||||
test_insert_throw();
|
||||
test_emplace_throw();
|
||||
test_resize_throw();
|
||||
test_insert_n_throw();
|
||||
#endif // !__clang__
|
||||
#endif // ASan instrumentation enabled
|
||||
}
|
|
@ -15,6 +15,7 @@ import itertools
|
|||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
import lit
|
||||
|
||||
|
@ -173,13 +174,14 @@ class STLTestFormat:
|
|||
if TestType.COMPILE in test.testType:
|
||||
cmd = [test.cxx, '-c', test.getSourcePath(), *test.flags, *test.compileFlags]
|
||||
yield TestStep(cmd, shared.execDir, shared.env, shouldFail)
|
||||
elif TestType.LINK in test.testType:
|
||||
elif TestType.LINK in test.testType or \
|
||||
('clang' in test.config.available_features and 'asan' in test.config.available_features):
|
||||
objFile = tmpBase + '.o'
|
||||
cmd = [test.cxx, '-c', test.getSourcePath(), *test.flags, *test.compileFlags, '-Fo' + objFile]
|
||||
yield TestStep(cmd, shared.execDir, shared.env, False)
|
||||
|
||||
exeFile = tmpBase + '.exe'
|
||||
cmd = [test.cxx, objFile, *test.flags, '-Fe' + exeFile, '-link', *test.linkFlags]
|
||||
shared.execFile = tmpBase + '.exe'
|
||||
cmd = ['link.exe', objFile, *test.flags, '-out:' + shared.execFile, *test.linkFlags]
|
||||
yield TestStep(cmd, shared.execDir, shared.env, shouldFail)
|
||||
elif TestType.RUN in test.testType:
|
||||
shared.execFile = tmpBase + '.exe'
|
||||
|
@ -239,7 +241,10 @@ class STLTestFormat:
|
|||
return (lit.Test.PASS, '')
|
||||
|
||||
except Exception as e:
|
||||
litConfig.error(repr(e))
|
||||
_, _, exception_traceback = sys.exc_info()
|
||||
filename = exception_traceback.tb_frame.f_code.co_filename
|
||||
line_number = exception_traceback.tb_lineno
|
||||
litConfig.error(repr(e) + ' at ' + filename + ':' + str(line_number))
|
||||
|
||||
|
||||
class LibcxxTestFormat(STLTestFormat):
|
||||
|
|
|
@ -53,7 +53,7 @@ class STLTest(Test):
|
|||
return result
|
||||
|
||||
self._parseTest()
|
||||
self._parseFlags()
|
||||
self._parseFlags(litConfig)
|
||||
|
||||
missing_required_features = self.getMissingRequiredFeatures()
|
||||
if missing_required_features:
|
||||
|
@ -204,6 +204,8 @@ class STLTest(Test):
|
|||
self.linkFlags.extend(self.envlstEntry.getEnvVal('PM_LINK', '').split())
|
||||
|
||||
if ('clang'.casefold() in os.path.basename(cxx).casefold()):
|
||||
self._addCustomFeature('clang')
|
||||
|
||||
targetArch = litConfig.target_arch.casefold()
|
||||
if (targetArch == 'x64'.casefold()):
|
||||
self.compileFlags.append('-m64')
|
||||
|
@ -213,10 +215,13 @@ class STLTest(Test):
|
|||
return Result(UNSUPPORTED, 'clang targeting arm is not supported')
|
||||
elif (targetArch == 'arm64'.casefold()):
|
||||
self.compileFlags.append('--target=arm64-pc-windows-msvc')
|
||||
elif ('nvcc'.casefold() in os.path.basename(cxx).casefold()):
|
||||
self._addCustomFeature('nvcc')
|
||||
|
||||
if ('nvcc'.casefold() in os.path.basename(cxx).casefold()):
|
||||
# nvcc only supports targeting x64
|
||||
self.requires.append('x64')
|
||||
else:
|
||||
self._addCustomFeature('cl')
|
||||
|
||||
self.cxx = os.path.normpath(cxx)
|
||||
return None
|
||||
|
@ -226,8 +231,9 @@ class STLTest(Test):
|
|||
for action in actions:
|
||||
action.applyTo(self.config)
|
||||
|
||||
def _parseFlags(self):
|
||||
def _parseFlags(self, litConfig):
|
||||
foundStd = False
|
||||
foundCRT = False
|
||||
for flag in chain(self.flags, self.compileFlags, self.linkFlags):
|
||||
if flag[1:5] == 'std:':
|
||||
foundStd = True
|
||||
|
@ -251,13 +257,41 @@ class STLTest(Test):
|
|||
self.requires.append('arch_ia32') # available for x86, see features.py
|
||||
elif flag[1:] == 'arch:VFPv4':
|
||||
self.requires.append('arch_vfpv4') # available for arm, see features.py
|
||||
elif flag[1:] == 'fsanitize=address':
|
||||
self._addCustomFeature('asan')
|
||||
elif flag[1:] == 'MDd':
|
||||
self._addCustomFeature('MDd')
|
||||
self._addCustomFeature('debug_CRT')
|
||||
self._addCustomFeature('dynamic_CRT')
|
||||
foundCRT = True
|
||||
elif flag[1:] == 'MD':
|
||||
self._addCustomFeature('MD')
|
||||
self._addCustomFeature('dynamic_CRT')
|
||||
foundCRT = True
|
||||
elif flag[1:] == 'MTd':
|
||||
self._addCustomFeature('MTd')
|
||||
self._addCustomFeature('debug_CRT')
|
||||
self._addCustomFeature('static_CRT')
|
||||
foundCRT = True
|
||||
elif flag[1:] == 'MT':
|
||||
self._addCustomFeature('MT')
|
||||
self._addCustomFeature('static_CRT')
|
||||
foundCRT = True
|
||||
|
||||
if not foundStd:
|
||||
self._addCustomFeature('c++14')
|
||||
|
||||
if not foundCRT:
|
||||
self._addCustomFeature('MT')
|
||||
self._addCustomFeature('static_CRT')
|
||||
|
||||
self._addCustomFeature('non-lockfree-atomics') # we always support non-lockfree-atomics
|
||||
self._addCustomFeature('is-lockfree-runtime-function') # Ditto
|
||||
|
||||
# clang doesn't know how to link in the VS version of the asan runtime automatically
|
||||
if 'asan' in self.config.available_features and 'clang' in self.config.available_features:
|
||||
self.linkFlags.append("/INFERASANLIBS")
|
||||
|
||||
|
||||
class LibcxxTest(STLTest):
|
||||
def getTestName(self):
|
||||
|
|
Загрузка…
Ссылка в новой задаче