зеркало из https://github.com/microsoft/STL.git
Re-enable ASAN string annotations (#3164)
Co-authored-by: Nicole Mazzuca <mazzucan@outlook.com>
This commit is contained in:
Родитель
67d89ce691
Коммит
faaf094ee1
|
@ -8,6 +8,7 @@ set(HEADERS
|
||||||
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_format_ucd_tables.hpp
|
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_format_ucd_tables.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_int128.hpp
|
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_int128.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_iter_core.hpp
|
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_iter_core.hpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_sanitizer_annotate_container.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_system_error_abi.hpp
|
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_system_error_abi.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_tzdb.hpp
|
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_tzdb.hpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_xlocinfo_types.hpp
|
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_xlocinfo_types.hpp
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
// __msvc_sanitizer_annotate_container.hpp internal header
|
||||||
|
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef __MSVC_SANITIZER_ANNOTATE_CONTAINER_HPP
|
||||||
|
#define __MSVC_SANITIZER_ANNOTATE_CONTAINER_HPP
|
||||||
|
#include <yvals_core.h>
|
||||||
|
#if _STL_COMPILER_PREPROCESSOR
|
||||||
|
|
||||||
|
#pragma pack(push, _CRT_PACKING)
|
||||||
|
#pragma warning(push, _STL_WARNING_LEVEL)
|
||||||
|
#pragma warning(disable : _STL_DISABLED_WARNINGS)
|
||||||
|
_STL_DISABLE_CLANG_WARNINGS
|
||||||
|
#pragma push_macro("new")
|
||||||
|
#undef new
|
||||||
|
|
||||||
|
#if !defined(_M_CEE_PURE) && !(defined(_DISABLE_STRING_ANNOTATION) && defined(_DISABLE_VECTOR_ANNOTATION))
|
||||||
|
|
||||||
|
#ifdef __SANITIZE_ADDRESS__
|
||||||
|
|
||||||
|
#define _ACTIVATE_STRING_ANNOTATION
|
||||||
|
#define _INSERT_STRING_ANNOTATION
|
||||||
|
#define _ACTIVATE_VECTOR_ANNOTATION
|
||||||
|
#define _INSERT_VECTOR_ANNOTATION
|
||||||
|
|
||||||
|
#elif defined(__clang__) // ^^^ __SANITIZE_ADDRESS__ / __clang__ vvv
|
||||||
|
|
||||||
|
#if __has_feature(address_sanitizer)
|
||||||
|
#define _ACTIVATE_STRING_ANNOTATION
|
||||||
|
#define _INSERT_STRING_ANNOTATION
|
||||||
|
#define _ACTIVATE_VECTOR_ANNOTATION
|
||||||
|
#define _INSERT_VECTOR_ANNOTATION
|
||||||
|
#pragma comment(linker, "/INFERASANLIBS")
|
||||||
|
#endif // __has_feature(address_sanitizer)
|
||||||
|
|
||||||
|
#else // ^^^ __clang__ / !__clang__ && !__SANITIZE_ADDRESS__ vvv
|
||||||
|
|
||||||
|
#ifdef _ANNOTATE_STRING
|
||||||
|
#define _INSERT_STRING_ANNOTATION
|
||||||
|
#endif // _ANNOTATE_STRING
|
||||||
|
#ifdef _ANNOTATE_VECTOR
|
||||||
|
#define _INSERT_VECTOR_ANNOTATION
|
||||||
|
#endif // _ANNOTATE_VECTOR
|
||||||
|
|
||||||
|
#endif // __SANITIZE_ADDRESS__
|
||||||
|
|
||||||
|
#ifdef _DISABLE_STRING_ANNOTATION
|
||||||
|
#undef _ACTIVATE_STRING_ANNOTATION
|
||||||
|
#undef _INSERT_STRING_ANNOTATION
|
||||||
|
#endif // _DISABLE_STRING_ANNOTATION
|
||||||
|
#ifdef _DISABLE_VECTOR_ANNOTATION
|
||||||
|
#undef _ACTIVATE_VECTOR_ANNOTATION
|
||||||
|
#undef _INSERT_VECTOR_ANNOTATION
|
||||||
|
#endif // _DISABLE_VECTOR_ANNOTATION
|
||||||
|
|
||||||
|
#ifndef _INSERT_STRING_ANNOTATION
|
||||||
|
#pragma detect_mismatch("annotate_string", "0")
|
||||||
|
#endif // !_INSERT_STRING_ANNOTATION
|
||||||
|
#ifndef _INSERT_VECTOR_ANNOTATION
|
||||||
|
#pragma detect_mismatch("annotate_vector", "0")
|
||||||
|
#endif // !_INSERT_VECTOR_ANNOTATION
|
||||||
|
|
||||||
|
#ifdef _ACTIVATE_STRING_ANNOTATION
|
||||||
|
#pragma comment(lib, "stl_asan")
|
||||||
|
#pragma detect_mismatch("annotate_string", "1")
|
||||||
|
#endif // _ACTIVATE_STRING_ANNOTATION
|
||||||
|
#ifdef _ACTIVATE_VECTOR_ANNOTATION
|
||||||
|
#pragma comment(lib, "stl_asan")
|
||||||
|
#pragma detect_mismatch("annotate_vector", "1")
|
||||||
|
#endif // _ACTIVATE_VECTOR_ANNOTATION
|
||||||
|
|
||||||
|
#undef _ACTIVATE_STRING_ANNOTATION
|
||||||
|
#undef _ACTIVATE_VECTOR_ANNOTATION
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#ifdef _INSERT_VECTOR_ANNOTATION
|
||||||
|
extern const bool _Asan_vector_should_annotate;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _INSERT_STRING_ANNOTATION
|
||||||
|
extern const bool _Asan_string_should_annotate;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_INSERT_VECTOR_ANNOTATION) || defined(_INSERT_STRING_ANNOTATION)
|
||||||
|
extern "C" {
|
||||||
|
void __cdecl __sanitizer_annotate_contiguous_container(
|
||||||
|
const void* _First, const void* _End, const void* _Old_last, const void* _New_last);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _M_ARM64EC
|
||||||
|
#pragma comment(linker, \
|
||||||
|
"/alternatename:#__sanitizer_annotate_contiguous_container=#__sanitizer_annotate_contiguous_container_default")
|
||||||
|
#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")
|
||||||
|
#pragma comment(linker, "/alternatename:_Asan_vector_should_annotate=_Asan_vector_should_annotate_default")
|
||||||
|
#pragma comment(linker, "/alternatename:#_Asan_string_should_annotate=#_Asan_string_should_annotate_default")
|
||||||
|
#pragma comment(linker, "/alternatename:_Asan_string_should_annotate=_Asan_string_should_annotate_default")
|
||||||
|
#elif defined(_M_HYBRID)
|
||||||
|
#pragma comment(linker, \
|
||||||
|
"/alternatename:#__sanitizer_annotate_contiguous_container=#__sanitizer_annotate_contiguous_container_default")
|
||||||
|
#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")
|
||||||
|
#pragma comment(linker, "/alternatename:__Asan_vector_should_annotate=__Asan_vector_should_annotate_default")
|
||||||
|
#pragma comment(linker, "/alternatename:#_Asan_string_should_annotate=#_Asan_string_should_annotate_default")
|
||||||
|
#pragma comment(linker, "/alternatename:__Asan_string_should_annotate=__Asan_string_should_annotate_default")
|
||||||
|
#elif 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")
|
||||||
|
#pragma comment(linker, "/alternatename:__Asan_string_should_annotate=__Asan_string_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")
|
||||||
|
#pragma comment(linker, "/alternatename:_Asan_string_should_annotate=_Asan_string_should_annotate_default")
|
||||||
|
#else // ^^^ known architecture / unknown architecture vvv
|
||||||
|
#error Unknown architecture
|
||||||
|
#endif // ^^^ unknown architecture ^^^
|
||||||
|
|
||||||
|
#endif // insert asan annotations
|
||||||
|
|
||||||
|
#endif // !_M_CEE_PURE && asan not disabled
|
||||||
|
|
||||||
|
#pragma pop_macro("new")
|
||||||
|
_STL_RESTORE_CLANG_WARNINGS
|
||||||
|
#pragma warning(pop)
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#endif // _STL_COMPILER_PREPROCESSOR
|
||||||
|
#endif // __MSVC_SANITIZER_ANNOTATE_CONTAINER_HPP
|
|
@ -10,6 +10,7 @@
|
||||||
"__msvc_format_ucd_tables.hpp",
|
"__msvc_format_ucd_tables.hpp",
|
||||||
"__msvc_int128.hpp",
|
"__msvc_int128.hpp",
|
||||||
"__msvc_iter_core.hpp",
|
"__msvc_iter_core.hpp",
|
||||||
|
"__msvc_sanitizer_annotate_container.hpp",
|
||||||
"__msvc_system_error_abi.hpp",
|
"__msvc_system_error_abi.hpp",
|
||||||
"__msvc_tzdb.hpp",
|
"__msvc_tzdb.hpp",
|
||||||
"__msvc_xlocinfo_types.hpp",
|
"__msvc_xlocinfo_types.hpp",
|
||||||
|
|
131
stl/inc/vector
131
stl/inc/vector
|
@ -14,6 +14,8 @@
|
||||||
#include <xpolymorphic_allocator.h>
|
#include <xpolymorphic_allocator.h>
|
||||||
#endif // _HAS_CXX17
|
#endif // _HAS_CXX17
|
||||||
|
|
||||||
|
#include <__msvc_sanitizer_annotate_container.hpp>
|
||||||
|
|
||||||
#pragma pack(push, _CRT_PACKING)
|
#pragma pack(push, _CRT_PACKING)
|
||||||
#pragma warning(push, _STL_WARNING_LEVEL)
|
#pragma warning(push, _STL_WARNING_LEVEL)
|
||||||
#pragma warning(disable : _STL_DISABLED_WARNINGS)
|
#pragma warning(disable : _STL_DISABLED_WARNINGS)
|
||||||
|
@ -426,70 +428,6 @@ constexpr _Ty* _Unfancy_maybe_null(_Ty* _Ptr) noexcept { // do nothing for plain
|
||||||
return _Ptr;
|
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__ / __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__ / _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_ARM64EC)
|
|
||||||
#pragma comment(linker, \
|
|
||||||
"/alternatename:#__sanitizer_annotate_contiguous_container=#__sanitizer_annotate_contiguous_container_default")
|
|
||||||
#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")
|
|
||||||
#pragma comment(linker, "/alternatename:_Asan_vector_should_annotate=_Asan_vector_should_annotate_default")
|
|
||||||
#elif defined(_M_HYBRID)
|
|
||||||
#pragma comment(linker, \
|
|
||||||
"/alternatename:#__sanitizer_annotate_contiguous_container=#__sanitizer_annotate_contiguous_container_default")
|
|
||||||
#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")
|
|
||||||
#pragma comment(linker, "/alternatename:__Asan_vector_should_annotate=__Asan_vector_should_annotate_default")
|
|
||||||
#elif 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")
|
|
||||||
#else // ^^^ known architecture / unknown architecture vvv
|
|
||||||
#error Unknown architecture
|
|
||||||
#endif // ^^^ unknown architecture ^^^
|
|
||||||
|
|
||||||
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 / !_INSERT_VECTOR_ANNOTATION vvv
|
|
||||||
#pragma detect_mismatch("annotate_vector", "0")
|
|
||||||
#endif // !_INSERT_VECTOR_ANNOTATION
|
|
||||||
|
|
||||||
_EXPORT_STD template <class _Ty, class _Alloc = allocator<_Ty>>
|
_EXPORT_STD template <class _Ty, class _Alloc = allocator<_Ty>>
|
||||||
class vector { // varying size array of values
|
class vector { // varying size array of values
|
||||||
private:
|
private:
|
||||||
|
@ -539,29 +477,6 @@ private:
|
||||||
_Apply_annotation(_My_data._Myfirst, _My_data._Myend, _My_data._Mylast, _My_data._Mylast + _Count);
|
_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(
|
static _CONSTEXPR20 void _Apply_annotation(
|
||||||
pointer _First_, pointer _End_, pointer _Old_last_, pointer _New_last_) noexcept {
|
pointer _First_, pointer _End_, pointer _Old_last_, pointer _New_last_) noexcept {
|
||||||
_STL_INTERNAL_CHECK(_First_ != nullptr);
|
_STL_INTERNAL_CHECK(_First_ != nullptr);
|
||||||
|
@ -579,24 +494,38 @@ private:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto _First = reinterpret_cast<const char*>(_Unfancy(_First_));
|
const void* const _First = _STD _Unfancy(_First_);
|
||||||
const auto _End = reinterpret_cast<const char*>(_Unfancy(_End_));
|
const void* const _End = _STD _Unfancy(_End_);
|
||||||
const auto _Old_last = reinterpret_cast<const char*>(_Unfancy(_Old_last_));
|
const void* const _Old_last = _STD _Unfancy(_Old_last_);
|
||||||
const auto _New_last = reinterpret_cast<const char*>(_Unfancy(_New_last_));
|
const void* const _New_last = _STD _Unfancy(_New_last_);
|
||||||
if constexpr (_Has_minimum_allocation_alignment<vector>) {
|
if constexpr ((_Container_allocation_minimum_asan_alignment<vector>) >= _Asan_granularity) {
|
||||||
__sanitizer_annotate_contiguous_container(_First, _End, _Old_last, _New_last);
|
// old state:
|
||||||
|
// [_First, _Old_last) valid
|
||||||
|
// [_Old_last, _End) poison
|
||||||
|
// new state:
|
||||||
|
// [_First, _New_last) valid
|
||||||
|
// [_New_last, asan_aligned_after(_End)) poison
|
||||||
|
_CSTD __sanitizer_annotate_contiguous_container(
|
||||||
|
_First, _STD _Get_asan_aligned_after(_End), _Old_last, _New_last);
|
||||||
} else {
|
} else {
|
||||||
const void* const _Aligned_first = _Get_aligned_first(_First, _End);
|
const auto _Aligned = _STD _Get_asan_aligned_first_end(_First, _End);
|
||||||
if (!_Aligned_first) {
|
if (_Aligned._First == _Aligned._End) {
|
||||||
// There is no aligned address within the underlying buffer; nothing to do.
|
// The buffer does not end at least one shadow memory section; nothing to do.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void* const _Aligned_old_last = _Old_last < _Aligned_first ? _Aligned_first : _Old_last;
|
const void* const _Old_fixed = _Aligned._Clamp_to_end(_Old_last);
|
||||||
const void* const _Aligned_new_last = _New_last < _Aligned_first ? _Aligned_first : _New_last;
|
const void* const _New_fixed = _Aligned._Clamp_to_end(_New_last);
|
||||||
const void* const _Aligned_end = _End < _Aligned_first ? _Aligned_first : _End;
|
|
||||||
__sanitizer_annotate_contiguous_container(
|
// old state:
|
||||||
_Aligned_first, _Aligned_end, _Aligned_old_last, _Aligned_new_last);
|
// [_Aligned._First, _Old_fixed) valid
|
||||||
|
// [_Old_fixed, _Aligned._End) poison
|
||||||
|
// [_Aligned._End, _End) valid
|
||||||
|
// new state:
|
||||||
|
// [_Aligned._First, _New_fixed) valid
|
||||||
|
// [_New_fixed, _Aligned._End) poison
|
||||||
|
// [_Aligned._End, _End) valid
|
||||||
|
_CSTD __sanitizer_annotate_contiguous_container(_Aligned._First, _Aligned._End, _Old_fixed, _New_fixed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
122
stl/inc/xmemory
122
stl/inc/xmemory
|
@ -775,6 +775,126 @@ _NODISCARD constexpr allocation_result<typename allocator_traits<_Alloc>::pointe
|
||||||
|
|
||||||
// The number of user bytes a single byte of ASAN shadow memory can track.
|
// The number of user bytes a single byte of ASAN shadow memory can track.
|
||||||
_INLINE_VAR constexpr size_t _Asan_granularity = 8;
|
_INLINE_VAR constexpr size_t _Asan_granularity = 8;
|
||||||
|
_INLINE_VAR constexpr size_t _Asan_granularity_mask = _Asan_granularity - 1;
|
||||||
|
|
||||||
|
struct _Asan_aligned_pointers {
|
||||||
|
const void* _First;
|
||||||
|
const void* _End;
|
||||||
|
|
||||||
|
_NODISCARD constexpr const void* _Clamp_to_end(const void* _Mid) const noexcept {
|
||||||
|
_STL_INTERNAL_CHECK(_Mid >= _First);
|
||||||
|
if (_Mid > _End) {
|
||||||
|
return _End;
|
||||||
|
} else {
|
||||||
|
return _Mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The way that ASan shadow memory works, each eight byte block of memory ("shadow memory section")
|
||||||
|
// has a single byte to mark it as either poison or valid.
|
||||||
|
// Each section has 0 to 8 "valid" bytes followed by poison bytes, so:
|
||||||
|
// ```
|
||||||
|
// [ v v v p p p p p ]
|
||||||
|
// ```
|
||||||
|
// or
|
||||||
|
// ```
|
||||||
|
// [ v v v v v v v v ]
|
||||||
|
// ```
|
||||||
|
// are okay, but
|
||||||
|
// ```
|
||||||
|
// [ p p p p v v v v ]
|
||||||
|
// ```
|
||||||
|
// is not.
|
||||||
|
//
|
||||||
|
// This function exists to fix up `first` and `end` pointers so that one can call
|
||||||
|
// `__sanitizer_annotate_contiguous_container`:
|
||||||
|
//
|
||||||
|
// - `__sanitizer_annotate_contiguous_container` checks that `first` is aligned to an 8-byte boundary
|
||||||
|
// - if `end` is not aligned to an 8-byte boundary, `__sanitizer_annotate_contiguous_container` still poisons the
|
||||||
|
// remaining bytes in the shadow memory section.
|
||||||
|
//
|
||||||
|
// Because of the second property, we can only mark poison up to the final aligned address before the true `last`.
|
||||||
|
// Otherwise, we'd poison the memory _after_ `last` as well.
|
||||||
|
// For the first property, we can assume that everything before `first` in the shadow memory section is valid
|
||||||
|
// (since otherwise we couldn't mark `first` valid), and so we just return back the first address in
|
||||||
|
// `first`'s shadow memory section.
|
||||||
|
//
|
||||||
|
// ### Example
|
||||||
|
//
|
||||||
|
// ```cpp
|
||||||
|
// struct alignas(8) cat {
|
||||||
|
// int meow; // bytes [0, 4)
|
||||||
|
// char buffer[16]; // bytes [4, 20)
|
||||||
|
// int purr; // bytes [20, 24)
|
||||||
|
// };
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// First, `meow` and `purr` are just regular data members, not container buffers, so they _must_ be valid.
|
||||||
|
// Then, assume we want to poison all of `buffer`.
|
||||||
|
// This would mean that, in a perfect world, we want something like:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// | meow | buffer | purr |
|
||||||
|
// [ v v v v p p p p ][ p p p p p p p p ][ p p p p v v v v ]
|
||||||
|
// sm1 sm2 sm3
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// However, note that by the rules above, `sm3` is not a valid shadow memory section; we always need
|
||||||
|
// the valid bytes to come before the poison bytes. Thus, the closest we can actually get to it is:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// | meow | buffer | purr |
|
||||||
|
// [ v v v v p p p p ][ p p p p p p p p ][ v v v v v v v v ]
|
||||||
|
// sm1 sm2 sm3
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// We call `aligned = _Get_asan_aligned_first_end(cat.buffer, cat.buffer + 16);`, and we get back
|
||||||
|
//
|
||||||
|
// ```cpp
|
||||||
|
// aligned = {
|
||||||
|
// ._First = &cat.meow,
|
||||||
|
// ._End = cat.buffer + 12,
|
||||||
|
// };
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// Then, we poison as much of buffer as we can via
|
||||||
|
//
|
||||||
|
// ```cpp
|
||||||
|
// __sanitizer_annotate_contiguous_container(
|
||||||
|
// aligned._First,
|
||||||
|
// aligned._End,
|
||||||
|
// cat.buffer,
|
||||||
|
// aligned._Clamp_to_end(cat.buffer + 16));
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// We are allowed to assume that `&cat.meow` is valid, since otherwise `cat.buffer + [0, 4)` could not be valid.
|
||||||
|
// We cannot poison up to `cat.buffer + 16`, since then `&purr` could not be valid.
|
||||||
|
// Thus, this results in the shadow memory state from the second example.
|
||||||
|
_NODISCARD inline _Asan_aligned_pointers _Get_asan_aligned_first_end(
|
||||||
|
const void* const _First, const void* const _End) noexcept {
|
||||||
|
return {
|
||||||
|
reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(_First) & ~_Asan_granularity_mask),
|
||||||
|
reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(_End) & ~_Asan_granularity_mask),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we can assume that the allocator we are using will always align allocations to the 8-byte,
|
||||||
|
// we can simply push the `_End` pointer to the end of the shadow memory section.
|
||||||
|
// This is _not_ safe in general (see _Get_asan_aligned_first_end's comment for why).
|
||||||
|
_NODISCARD inline const void* _Get_asan_aligned_after(const void* const _End) noexcept {
|
||||||
|
return reinterpret_cast<const void*>(
|
||||||
|
(reinterpret_cast<uintptr_t>(_End) + _Asan_granularity_mask) & ~_Asan_granularity_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Container, class = void>
|
||||||
|
_INLINE_VAR constexpr size_t _Container_allocation_minimum_asan_alignment = alignof(typename _Container::value_type);
|
||||||
|
|
||||||
|
template <class _Container>
|
||||||
|
_INLINE_VAR constexpr size_t _Container_allocation_minimum_asan_alignment<_Container,
|
||||||
|
void_t<decltype(_Container::allocator_type::_Minimum_asan_allocation_alignment)>> =
|
||||||
|
(_STD max)(
|
||||||
|
alignof(typename _Container::value_type), _Container::allocator_type::_Minimum_asan_allocation_alignment);
|
||||||
|
|
||||||
_EXPORT_STD template <class _Ty>
|
_EXPORT_STD template <class _Ty>
|
||||||
class allocator {
|
class allocator {
|
||||||
|
@ -862,7 +982,7 @@ public:
|
||||||
}
|
}
|
||||||
#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
||||||
|
|
||||||
static constexpr size_t _Minimum_allocation_alignment = _Asan_granularity;
|
static constexpr size_t _Minimum_asan_allocation_alignment = _Asan_granularity;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if _HAS_DEPRECATED_ALLOCATOR_VOID || _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
#if _HAS_DEPRECATED_ALLOCATOR_VOID || _HAS_DEPRECATED_ALLOCATOR_MEMBERS
|
||||||
|
|
280
stl/inc/xstring
280
stl/inc/xstring
|
@ -17,6 +17,8 @@
|
||||||
#include <xpolymorphic_allocator.h>
|
#include <xpolymorphic_allocator.h>
|
||||||
#endif // _HAS_CXX17
|
#endif // _HAS_CXX17
|
||||||
|
|
||||||
|
#include <__msvc_sanitizer_annotate_container.hpp>
|
||||||
|
|
||||||
#pragma pack(push, _CRT_PACKING)
|
#pragma pack(push, _CRT_PACKING)
|
||||||
#pragma warning(push, _STL_WARNING_LEVEL)
|
#pragma warning(push, _STL_WARNING_LEVEL)
|
||||||
#pragma warning(disable : _STL_DISABLED_WARNINGS)
|
#pragma warning(disable : _STL_DISABLED_WARNINGS)
|
||||||
|
@ -2350,73 +2352,6 @@ struct _String_constructor_rvalue_allocator_tag {
|
||||||
_Xlength_error("string too long");
|
_Xlength_error("string too long");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 // TRANSITION, VSO-1586016: String annotations disabled temporarily.
|
|
||||||
#if !defined(_M_CEE_PURE) && !defined(_DISABLE_STRING_ANNOTATION)
|
|
||||||
#if defined(__SANITIZE_ADDRESS__)
|
|
||||||
#define _ACTIVATE_STRING_ANNOTATION
|
|
||||||
#define _INSERT_STRING_ANNOTATION
|
|
||||||
#elif defined(__clang__) && defined(__has_feature) // ^^^ __SANITIZE_ADDRESS__ / __clang__ vvv
|
|
||||||
#if __has_feature(address_sanitizer)
|
|
||||||
#define _ACTIVATE_STRING_ANNOTATION
|
|
||||||
#define _INSERT_STRING_ANNOTATION
|
|
||||||
#pragma comment(linker, "/INFERASANLIBS")
|
|
||||||
#endif // __has_feature(address_sanitizer)
|
|
||||||
#elif defined(_ANNOTATE_STRING) // ^^^ __clang__ / _ANNOTATE_STRING vvv
|
|
||||||
#define _INSERT_STRING_ANNOTATION
|
|
||||||
#endif // _ANNOTATE_STRING
|
|
||||||
#endif // !_M_CEE_PURE && !_DISABLE_STRING_ANNOTATION
|
|
||||||
|
|
||||||
#ifdef _ACTIVATE_STRING_ANNOTATION
|
|
||||||
#pragma comment(lib, "stl_asan")
|
|
||||||
#pragma detect_mismatch("annotate_string", "1")
|
|
||||||
#endif // _ACTIVATE_STRING_ANNOTATION
|
|
||||||
#endif // TRANSITION, VSO-1586016
|
|
||||||
|
|
||||||
#ifdef _INSERT_STRING_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_string_should_annotate;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(_M_ARM64EC)
|
|
||||||
#pragma comment(linker, \
|
|
||||||
"/alternatename:#__sanitizer_annotate_contiguous_container=#__sanitizer_annotate_contiguous_container_default")
|
|
||||||
#pragma comment(linker, \
|
|
||||||
"/alternatename:__sanitizer_annotate_contiguous_container=__sanitizer_annotate_contiguous_container_default")
|
|
||||||
#pragma comment(linker, "/alternatename:#_Asan_string_should_annotate=#_Asan_string_should_annotate_default")
|
|
||||||
#pragma comment(linker, "/alternatename:_Asan_string_should_annotate=_Asan_string_should_annotate_default")
|
|
||||||
#elif defined(_M_HYBRID)
|
|
||||||
#pragma comment(linker, \
|
|
||||||
"/alternatename:#__sanitizer_annotate_contiguous_container=#__sanitizer_annotate_contiguous_container_default")
|
|
||||||
#pragma comment(linker, \
|
|
||||||
"/alternatename:___sanitizer_annotate_contiguous_container=___sanitizer_annotate_contiguous_container_default")
|
|
||||||
#pragma comment(linker, "/alternatename:#_Asan_string_should_annotate=#_Asan_string_should_annotate_default")
|
|
||||||
#pragma comment(linker, "/alternatename:__Asan_string_should_annotate=__Asan_string_should_annotate_default")
|
|
||||||
#elif defined(_M_IX86)
|
|
||||||
#pragma comment(linker, \
|
|
||||||
"/alternatename:___sanitizer_annotate_contiguous_container=___sanitizer_annotate_contiguous_container_default")
|
|
||||||
#pragma comment(linker, "/alternatename:__Asan_string_should_annotate=__Asan_string_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_string_should_annotate=_Asan_string_should_annotate_default")
|
|
||||||
#else // ^^^ known architecture / unknown architecture vvv
|
|
||||||
#error Unknown architecture
|
|
||||||
#endif // ^^^ unknown architecture ^^^
|
|
||||||
|
|
||||||
template <class _String, class = void>
|
|
||||||
_INLINE_VAR constexpr bool _Has_minimum_allocation_alignment_string =
|
|
||||||
alignof(typename _String::value_type) >= _Asan_granularity;
|
|
||||||
|
|
||||||
template <class _String>
|
|
||||||
_INLINE_VAR constexpr bool _Has_minimum_allocation_alignment_string<_String,
|
|
||||||
void_t<decltype(_String::allocator_type::_Minimum_allocation_alignment)>> =
|
|
||||||
_String::allocator_type::_Minimum_allocation_alignment >= _Asan_granularity;
|
|
||||||
#else // ^^^ _INSERT_STRING_ANNOTATION / !_INSERT_STRING_ANNOTATION vvv
|
|
||||||
#pragma detect_mismatch("annotate_string", "0")
|
|
||||||
#endif // !_INSERT_STRING_ANNOTATION
|
|
||||||
|
|
||||||
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
|
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
|
||||||
template <class _Rng, class _Ty>
|
template <class _Rng, class _Ty>
|
||||||
concept _Contiguous_range_of =
|
concept _Contiguous_range_of =
|
||||||
|
@ -2510,91 +2445,79 @@ private:
|
||||||
_Apply_annotation(_My_data._Myptr(), _My_data._Myres, _My_data._Mysize, _My_data._Myres);
|
_Apply_annotation(_My_data._Myptr(), _My_data._Myres, _My_data._Mysize, _My_data._Myres);
|
||||||
}
|
}
|
||||||
|
|
||||||
_CONSTEXPR20 void _Modify_annotation(const difference_type _Count) const noexcept {
|
_CONSTEXPR20 void _Modify_annotation(const size_type _Old_size, const size_type _New_size) const noexcept {
|
||||||
// Extends/shrinks the annotated range by _Count
|
if (_Old_size == _New_size) {
|
||||||
if (_Count == 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& _My_data = _Mypair._Myval2;
|
auto& _My_data = _Mypair._Myval2;
|
||||||
_Apply_annotation(
|
_Apply_annotation(_My_data._Myptr(), _My_data._Myres, _Old_size, _New_size);
|
||||||
_My_data._Myptr(), _My_data._Myres, _My_data._Mysize, static_cast<size_type>(_My_data._Mysize + _Count));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_NODISCARD static const void* _Get_aligned_first(const void* _First, const size_type _Capacity) noexcept {
|
static _CONSTEXPR20 void _Apply_annotation(const value_type* const _First, const size_type _Capacity,
|
||||||
const char* _CFirst = reinterpret_cast<const char*>(_First);
|
|
||||||
|
|
||||||
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(const value_type* _Ptr, const size_type _Capacity,
|
|
||||||
const size_type _Old_size, const size_type _New_size) noexcept {
|
const size_type _Old_size, const size_type _New_size) noexcept {
|
||||||
#if _HAS_CXX20
|
#if _HAS_CXX20
|
||||||
if (_STD is_constant_evaluated()) {
|
if (_STD is_constant_evaluated()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif // _HAS_CXX20
|
#endif // _HAS_CXX20
|
||||||
|
// Don't annotate small strings; only annotate on the heap.
|
||||||
if (!_Asan_string_should_annotate) {
|
if (_Capacity == _BUF_SIZE - 1 || !_Asan_string_should_annotate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to check whether we have a misaligned SSO buffer because of the proxy in `_Container_base` (e.g. x86)
|
// Note that `_Capacity`, `_Old_size`, and `_New_size` do not include the null terminator
|
||||||
if constexpr (_Memcpy_val_offset % _Asan_granularity != 0) {
|
const void* const _End = _First + _Capacity + 1;
|
||||||
const uintptr_t _Alignment_offset = reinterpret_cast<uintptr_t>(_Ptr) & (_Asan_granularity - 1);
|
const void* const _Old_last = _First + _Old_size + 1;
|
||||||
if (_Alignment_offset != 0 && _Capacity == _BUF_SIZE - 1) {
|
const void* const _New_last = _First + _New_size + 1;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Needs to consider the null terminator
|
constexpr bool _Large_string_always_asan_aligned =
|
||||||
const char* _First = reinterpret_cast<const char*>(_Ptr);
|
(_Container_allocation_minimum_asan_alignment<basic_string>) >= _Asan_granularity;
|
||||||
const char* _End = reinterpret_cast<const char*>(_Ptr + _Capacity + 1);
|
|
||||||
const char* _Old_last = reinterpret_cast<const char*>(_Ptr + _Old_size + 1);
|
// for the non-aligned buffer options, the buffer must always have size >= 9 bytes,
|
||||||
const char* _New_last = reinterpret_cast<const char*>(_Ptr + _New_size + 1);
|
// so it will always end at least one shadow memory section.
|
||||||
if constexpr (_Has_minimum_allocation_alignment_string<basic_string>) {
|
|
||||||
__sanitizer_annotate_contiguous_container(_First, _End, _Old_last, _New_last);
|
_Asan_aligned_pointers _Aligned;
|
||||||
|
if constexpr (_Large_string_always_asan_aligned) {
|
||||||
|
_Aligned = {_First, _STD _Get_asan_aligned_after(_End)};
|
||||||
} else {
|
} else {
|
||||||
const void* _Aligned_first = _Get_aligned_first(_First, _Capacity + 1);
|
_Aligned = _STD _Get_asan_aligned_first_end(_First, _End);
|
||||||
if (!_Aligned_first) {
|
}
|
||||||
// There is no aligned address within the underlying buffer. Nothing to do
|
const void* const _Old_fixed = _Aligned._Clamp_to_end(_Old_last);
|
||||||
return;
|
const void* const _New_fixed = _Aligned._Clamp_to_end(_New_last);
|
||||||
|
|
||||||
|
// --- always aligned case ---
|
||||||
|
// old state:
|
||||||
|
// [_First, _Old_last) valid
|
||||||
|
// [_Old_last, asan_aligned_after(_End)) poison
|
||||||
|
// new state:
|
||||||
|
// [_First, _New_last) valid
|
||||||
|
// [_New_last, asan_aligned_after(_End)) poison
|
||||||
|
|
||||||
|
// --- sometimes non-aligned case ---
|
||||||
|
// old state:
|
||||||
|
// [_Aligned._First, _Old_fixed) valid
|
||||||
|
// [_Old_fixed, _Aligned._End) poison
|
||||||
|
// [_Aligned._End, _End) valid
|
||||||
|
// new state:
|
||||||
|
// [_Aligned._First, _New_fixed) valid
|
||||||
|
// [_New_fixed, _Aligned._End) poison
|
||||||
|
// [_Aligned._End, _End) valid
|
||||||
|
_CSTD __sanitizer_annotate_contiguous_container(_Aligned._First, _Aligned._End, _Old_fixed, _New_fixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
const void* _Aligned_old_last = _Old_last < _Aligned_first ? _Aligned_first : _Old_last;
|
|
||||||
const void* _Aligned_new_last = _New_last < _Aligned_first ? _Aligned_first : _New_last;
|
|
||||||
const void* _Aligned_end = _End < _Aligned_first ? _Aligned_first : _End;
|
|
||||||
__sanitizer_annotate_contiguous_container(
|
|
||||||
_Aligned_first, _Aligned_end, _Aligned_old_last, _Aligned_new_last);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define _ASAN_STRING_MODIFY(n) _Modify_annotation((n))
|
|
||||||
#define _ASAN_STRING_REMOVE(_Str) (_Str)._Remove_annotation()
|
#define _ASAN_STRING_REMOVE(_Str) (_Str)._Remove_annotation()
|
||||||
#define _ASAN_STRING_CREATE(_Str) (_Str)._Create_annotation()
|
#define _ASAN_STRING_CREATE(_Str) (_Str)._Create_annotation()
|
||||||
|
#define _ASAN_STRING_MODIFY(_Str, _Old_size, _New_size) (_Str)._Modify_annotation(_Old_size, _New_size)
|
||||||
#else // ^^^ _INSERT_STRING_ANNOTATION / !_INSERT_STRING_ANNOTATION vvv
|
#else // ^^^ _INSERT_STRING_ANNOTATION / !_INSERT_STRING_ANNOTATION vvv
|
||||||
#define _ASAN_STRING_MODIFY(n)
|
|
||||||
#define _ASAN_STRING_REMOVE(_Str)
|
#define _ASAN_STRING_REMOVE(_Str)
|
||||||
#define _ASAN_STRING_CREATE(_Str)
|
#define _ASAN_STRING_CREATE(_Str)
|
||||||
|
#define _ASAN_STRING_MODIFY(_Str, _Old_size, _New_size)
|
||||||
#endif // !_INSERT_STRING_ANNOTATION
|
#endif // !_INSERT_STRING_ANNOTATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
_CONSTEXPR20 basic_string() noexcept(is_nothrow_default_constructible_v<_Alty>)
|
_CONSTEXPR20
|
||||||
: _Mypair(_Zero_then_variadic_args_t{}) {
|
basic_string() noexcept(is_nothrow_default_constructible_v<_Alty>) : _Mypair(_Zero_then_variadic_args_t{}) {
|
||||||
_Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal()));
|
_Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal()));
|
||||||
_Tidy_init();
|
_Tidy_init();
|
||||||
}
|
}
|
||||||
|
@ -2730,6 +2653,7 @@ private:
|
||||||
if (_Count < _BUF_SIZE) {
|
if (_Count < _BUF_SIZE) {
|
||||||
_My_data._Mysize = _Count;
|
_My_data._Mysize = _Count;
|
||||||
_My_data._Myres = _BUF_SIZE - 1;
|
_My_data._Myres = _BUF_SIZE - 1;
|
||||||
|
|
||||||
if constexpr (_Strat == _Construct_strategy::_From_char) {
|
if constexpr (_Strat == _Construct_strategy::_From_char) {
|
||||||
_Traits::assign(_My_data._Bx._Buf, _Count, _Arg);
|
_Traits::assign(_My_data._Bx._Buf, _Count, _Arg);
|
||||||
_Traits::assign(_My_data._Bx._Buf[_Count], _Elem());
|
_Traits::assign(_My_data._Bx._Buf[_Count], _Elem());
|
||||||
|
@ -2744,7 +2668,6 @@ private:
|
||||||
#endif // !_INSERT_STRING_ANNOTATION
|
#endif // !_INSERT_STRING_ANNOTATION
|
||||||
}
|
}
|
||||||
|
|
||||||
_ASAN_STRING_CREATE(*this);
|
|
||||||
_Proxy._Release();
|
_Proxy._Release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2947,7 +2870,7 @@ public:
|
||||||
_My_data._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); // throws, hereafter nothrow in this block
|
_My_data._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); // throws, hereafter nothrow in this block
|
||||||
_Take_contents(_Left);
|
_Take_contents(_Left);
|
||||||
const auto _Ptr = _My_data._Myptr();
|
const auto _Ptr = _My_data._Myptr();
|
||||||
_ASAN_STRING_MODIFY(static_cast<difference_type>(_Right_size));
|
_ASAN_STRING_MODIFY(*this, _Left_size, _New_size);
|
||||||
_Traits::copy(_Ptr + _Left_size, _Right_data._Myptr(), _Right_size + 1);
|
_Traits::copy(_Ptr + _Left_size, _Right_data._Myptr(), _Right_size + 1);
|
||||||
_My_data._Mysize = _New_size;
|
_My_data._Mysize = _New_size;
|
||||||
return;
|
return;
|
||||||
|
@ -2968,7 +2891,7 @@ public:
|
||||||
_My_data._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); // throws, hereafter nothrow in this block
|
_My_data._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); // throws, hereafter nothrow in this block
|
||||||
_Take_contents(_Right);
|
_Take_contents(_Right);
|
||||||
const auto _Ptr = _Unfancy(_My_data._Bx._Ptr);
|
const auto _Ptr = _Unfancy(_My_data._Bx._Ptr);
|
||||||
_ASAN_STRING_MODIFY(static_cast<difference_type>(_Left_size));
|
_ASAN_STRING_MODIFY(*this, _Right_size, _New_size);
|
||||||
_Traits::move(_Ptr + _Left_size, _Ptr, _Right_size + 1);
|
_Traits::move(_Ptr + _Left_size, _Ptr, _Right_size + 1);
|
||||||
_Traits::copy(_Ptr, _Left_data._Myptr(), _Left_size);
|
_Traits::copy(_Ptr, _Left_data._Myptr(), _Left_size);
|
||||||
_My_data._Mysize = _New_size;
|
_My_data._Mysize = _New_size;
|
||||||
|
@ -3042,7 +2965,6 @@ public:
|
||||||
_My_data._Myres = _Res - 1;
|
_My_data._Myres = _Res - 1;
|
||||||
_ASAN_STRING_CREATE(*this);
|
_ASAN_STRING_CREATE(*this);
|
||||||
} else {
|
} else {
|
||||||
_ASAN_STRING_MODIFY(static_cast<difference_type>(_Size));
|
|
||||||
_Traits::copy(_My_data._Bx._Buf, _Right, _Res);
|
_Traits::copy(_My_data._Bx._Buf, _Right, _Res);
|
||||||
_My_data._Mysize = _Size;
|
_My_data._Mysize = _Size;
|
||||||
_My_data._Myres = _BUF_SIZE - 1;
|
_My_data._Myres = _BUF_SIZE - 1;
|
||||||
|
@ -3131,6 +3053,7 @@ private:
|
||||||
auto& _My_data = _Mypair._Myval2;
|
auto& _My_data = _Mypair._Myval2;
|
||||||
auto& _Right_data = _Right._Mypair._Myval2;
|
auto& _Right_data = _Right._Mypair._Myval2;
|
||||||
|
|
||||||
|
#if !defined(_INSERT_STRING_ANNOTATION)
|
||||||
if constexpr (_Can_memcpy_val) {
|
if constexpr (_Can_memcpy_val) {
|
||||||
#if _HAS_CXX20
|
#if _HAS_CXX20
|
||||||
if (!_STD is_constant_evaluated())
|
if (!_STD is_constant_evaluated())
|
||||||
|
@ -3145,25 +3068,12 @@ private:
|
||||||
}
|
}
|
||||||
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
||||||
|
|
||||||
#ifdef _INSERT_STRING_ANNOTATION
|
|
||||||
if (!_Right_data._Large_string_engaged()) {
|
|
||||||
_ASAN_STRING_REMOVE(_Right);
|
|
||||||
}
|
|
||||||
#endif // _INSERT_STRING_ANNOTATION
|
|
||||||
|
|
||||||
_Memcpy_val_from(_Right);
|
_Memcpy_val_from(_Right);
|
||||||
|
|
||||||
#ifdef _INSERT_STRING_ANNOTATION
|
|
||||||
if (!_Right_data._Large_string_engaged()) {
|
|
||||||
_ASAN_STRING_REMOVE(_Right);
|
|
||||||
_ASAN_STRING_CREATE(*this);
|
|
||||||
}
|
|
||||||
#endif // _INSERT_STRING_ANNOTATION
|
|
||||||
|
|
||||||
_Right._Tidy_init();
|
_Right._Tidy_init();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !defined(_INSERT_STRING_ANNOTATION)
|
||||||
|
|
||||||
if (_Right_data._Large_string_engaged()) { // steal buffer
|
if (_Right_data._Large_string_engaged()) { // steal buffer
|
||||||
_Construct_in_place(_My_data._Bx._Ptr, _Right_data._Bx._Ptr);
|
_Construct_in_place(_My_data._Bx._Ptr, _Right_data._Bx._Ptr);
|
||||||
|
@ -3175,8 +3085,10 @@ private:
|
||||||
_Right_data._Orphan_all();
|
_Right_data._Orphan_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
_My_data._Mysize = _Right_data._Mysize;
|
|
||||||
_My_data._Myres = _Right_data._Myres;
|
_My_data._Myres = _Right_data._Myres;
|
||||||
|
_My_data._Mysize = _Right_data._Mysize;
|
||||||
|
|
||||||
|
|
||||||
_Right._Tidy_init();
|
_Right._Tidy_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3265,6 +3177,7 @@ private:
|
||||||
_CONSTEXPR20 void _Copy_assign_val_from_small(const basic_string& _Right) {
|
_CONSTEXPR20 void _Copy_assign_val_from_small(const basic_string& _Right) {
|
||||||
// TRANSITION, VSO-761321; inline into only caller when that's fixed
|
// TRANSITION, VSO-761321; inline into only caller when that's fixed
|
||||||
_Tidy_deallocate();
|
_Tidy_deallocate();
|
||||||
|
#if !defined(_INSERT_STRING_ANNOTATION)
|
||||||
if constexpr (_Can_memcpy_val) {
|
if constexpr (_Can_memcpy_val) {
|
||||||
#if _HAS_CXX20
|
#if _HAS_CXX20
|
||||||
if (!_STD is_constant_evaluated())
|
if (!_STD is_constant_evaluated())
|
||||||
|
@ -3274,6 +3187,7 @@ private:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !defined(_INSERT_STRING_ANNOTATION)
|
||||||
|
|
||||||
auto& _My_data = _Mypair._Myval2;
|
auto& _My_data = _Mypair._Myval2;
|
||||||
auto& _Right_data = _Right._Mypair._Myval2;
|
auto& _Right_data = _Right._Mypair._Myval2;
|
||||||
|
@ -3345,7 +3259,7 @@ public:
|
||||||
#endif // _HAS_CXX23
|
#endif // _HAS_CXX23
|
||||||
|
|
||||||
_CONSTEXPR20 basic_string& operator=(const _Elem _Ch) { // assign {_Ch, _Elem()}
|
_CONSTEXPR20 basic_string& operator=(const _Elem _Ch) { // assign {_Ch, _Elem()}
|
||||||
_ASAN_STRING_MODIFY(static_cast<difference_type>(1 - _Mypair._Myval2._Mysize));
|
_ASAN_STRING_MODIFY(*this, _Mypair._Myval2._Mysize, 1);
|
||||||
_Mypair._Myval2._Mysize = 1;
|
_Mypair._Myval2._Mysize = 1;
|
||||||
_Elem* const _Ptr = _Mypair._Myval2._Myptr();
|
_Elem* const _Ptr = _Mypair._Myval2._Myptr();
|
||||||
_Traits::assign(_Ptr[0], _Ch);
|
_Traits::assign(_Ptr[0], _Ch);
|
||||||
|
@ -3405,7 +3319,7 @@ public:
|
||||||
// append [_Ptr, _Ptr + _Count)
|
// append [_Ptr, _Ptr + _Count)
|
||||||
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
||||||
if (_Count <= _Mypair._Myval2._Myres - _Old_size) {
|
if (_Count <= _Mypair._Myval2._Myres - _Old_size) {
|
||||||
_ASAN_STRING_MODIFY(static_cast<difference_type>(_Count));
|
_ASAN_STRING_MODIFY(*this, _Old_size, _Old_size + _Count);
|
||||||
_Mypair._Myval2._Mysize = _Old_size + _Count;
|
_Mypair._Myval2._Mysize = _Old_size + _Count;
|
||||||
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
||||||
_Traits::move(_Old_ptr + _Old_size, _Ptr, _Count);
|
_Traits::move(_Old_ptr + _Old_size, _Ptr, _Count);
|
||||||
|
@ -3432,7 +3346,7 @@ public:
|
||||||
// append _Count * _Ch
|
// append _Count * _Ch
|
||||||
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
||||||
if (_Count <= _Mypair._Myval2._Myres - _Old_size) {
|
if (_Count <= _Mypair._Myval2._Myres - _Old_size) {
|
||||||
_ASAN_STRING_MODIFY(static_cast<difference_type>(_Count));
|
_ASAN_STRING_MODIFY(*this, _Old_size, _Old_size + _Count);
|
||||||
_Mypair._Myval2._Mysize = _Old_size + _Count;
|
_Mypair._Myval2._Mysize = _Old_size + _Count;
|
||||||
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
||||||
_Traits::assign(_Old_ptr + _Old_size, _Count, _Ch);
|
_Traits::assign(_Old_ptr + _Old_size, _Count, _Ch);
|
||||||
|
@ -3510,7 +3424,7 @@ public:
|
||||||
_In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) {
|
_In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) {
|
||||||
// assign [_Ptr, _Ptr + _Count)
|
// assign [_Ptr, _Ptr + _Count)
|
||||||
if (_Count <= _Mypair._Myval2._Myres) {
|
if (_Count <= _Mypair._Myval2._Myres) {
|
||||||
_ASAN_STRING_MODIFY(static_cast<difference_type>(_Count - _Mypair._Myval2._Mysize));
|
_ASAN_STRING_MODIFY(*this, _Mypair._Myval2._Mysize, _Count);
|
||||||
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
||||||
_Mypair._Myval2._Mysize = _Count;
|
_Mypair._Myval2._Mysize = _Count;
|
||||||
_Traits::move(_Old_ptr, _Ptr, _Count);
|
_Traits::move(_Old_ptr, _Ptr, _Count);
|
||||||
|
@ -3534,7 +3448,7 @@ public:
|
||||||
_CONSTEXPR20 basic_string& assign(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) {
|
_CONSTEXPR20 basic_string& assign(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) {
|
||||||
// assign _Count * _Ch
|
// assign _Count * _Ch
|
||||||
if (_Count <= _Mypair._Myval2._Myres) {
|
if (_Count <= _Mypair._Myval2._Myres) {
|
||||||
_ASAN_STRING_MODIFY(static_cast<difference_type>(_Count - _Mypair._Myval2._Mysize));
|
_ASAN_STRING_MODIFY(*this, _Mypair._Myval2._Mysize, _Count);
|
||||||
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
||||||
_Mypair._Myval2._Mysize = _Count;
|
_Mypair._Myval2._Mysize = _Count;
|
||||||
_Traits::assign(_Old_ptr, _Count, _Ch);
|
_Traits::assign(_Old_ptr, _Count, _Ch);
|
||||||
|
@ -3634,7 +3548,7 @@ public:
|
||||||
#endif // _HAS_CXX20
|
#endif // _HAS_CXX20
|
||||||
|
|
||||||
if (_Check_overlap) {
|
if (_Check_overlap) {
|
||||||
_ASAN_STRING_MODIFY(static_cast<difference_type>(_Count));
|
_ASAN_STRING_MODIFY(*this, _Old_size, _Old_size + _Count);
|
||||||
_Mypair._Myval2._Mysize = _Old_size + _Count;
|
_Mypair._Myval2._Mysize = _Old_size + _Count;
|
||||||
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
||||||
_Elem* const _Insert_at = _Old_ptr + _Off;
|
_Elem* const _Insert_at = _Old_ptr + _Off;
|
||||||
|
@ -3679,7 +3593,7 @@ public:
|
||||||
_Mypair._Myval2._Check_offset(_Off);
|
_Mypair._Myval2._Check_offset(_Off);
|
||||||
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
||||||
if (_Count <= _Mypair._Myval2._Myres - _Old_size) {
|
if (_Count <= _Mypair._Myval2._Myres - _Old_size) {
|
||||||
_ASAN_STRING_MODIFY(static_cast<difference_type>(_Count));
|
_ASAN_STRING_MODIFY(*this, _Old_size, _Old_size + _Count);
|
||||||
_Mypair._Myval2._Mysize = _Old_size + _Count;
|
_Mypair._Myval2._Mysize = _Old_size + _Count;
|
||||||
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
||||||
_Elem* const _Insert_at = _Old_ptr + _Off;
|
_Elem* const _Insert_at = _Old_ptr + _Off;
|
||||||
|
@ -3773,7 +3687,7 @@ private:
|
||||||
_Elem* const _Erase_at = _My_ptr + _Off;
|
_Elem* const _Erase_at = _My_ptr + _Off;
|
||||||
const size_type _New_size = _Old_size - _Count;
|
const size_type _New_size = _Old_size - _Count;
|
||||||
_Traits::move(_Erase_at, _Erase_at + _Count, _New_size - _Off + 1); // move suffix + null up
|
_Traits::move(_Erase_at, _Erase_at + _Count, _New_size - _Off + 1); // move suffix + null up
|
||||||
_ASAN_STRING_MODIFY(-static_cast<difference_type>(_Count));
|
_ASAN_STRING_MODIFY(*this, _Old_size, _New_size);
|
||||||
_Mypair._Myval2._Mysize = _New_size;
|
_Mypair._Myval2._Mysize = _New_size;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -3852,11 +3766,14 @@ public:
|
||||||
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
||||||
const size_type _Suffix_size = _Old_size - _Nx - _Off + 1;
|
const size_type _Suffix_size = _Old_size - _Nx - _Off + 1;
|
||||||
if (_Count < _Nx) { // suffix shifts backwards; we don't have to move anything out of the way
|
if (_Count < _Nx) { // suffix shifts backwards; we don't have to move anything out of the way
|
||||||
_Mypair._Myval2._Mysize = _Old_size - (_Nx - _Count);
|
|
||||||
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
||||||
_Elem* const _Insert_at = _Old_ptr + _Off;
|
_Elem* const _Insert_at = _Old_ptr + _Off;
|
||||||
_Traits::move(_Insert_at, _Ptr, _Count);
|
_Traits::move(_Insert_at, _Ptr, _Count);
|
||||||
_Traits::move(_Insert_at + _Count, _Insert_at + _Nx, _Suffix_size);
|
_Traits::move(_Insert_at + _Count, _Insert_at + _Nx, _Suffix_size);
|
||||||
|
|
||||||
|
const auto _New_size = _Old_size - (_Nx - _Count);
|
||||||
|
_ASAN_STRING_MODIFY(*this, _Old_size, _New_size);
|
||||||
|
_Mypair._Myval2._Mysize = _New_size;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3869,6 +3786,7 @@ public:
|
||||||
#endif // _HAS_CXX20
|
#endif // _HAS_CXX20
|
||||||
{
|
{
|
||||||
if (_Growth <= _Mypair._Myval2._Myres - _Old_size) { // growth fits
|
if (_Growth <= _Mypair._Myval2._Myres - _Old_size) { // growth fits
|
||||||
|
_ASAN_STRING_MODIFY(*this, _Old_size, _Old_size + _Growth);
|
||||||
_Mypair._Myval2._Mysize = _Old_size + _Growth;
|
_Mypair._Myval2._Mysize = _Old_size + _Growth;
|
||||||
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
||||||
_Elem* const _Insert_at = _Old_ptr + _Off;
|
_Elem* const _Insert_at = _Old_ptr + _Off;
|
||||||
|
@ -3924,8 +3842,10 @@ public:
|
||||||
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
||||||
if (_Count < _Nx || _Count - _Nx <= _Mypair._Myval2._Myres - _Old_size) {
|
if (_Count < _Nx || _Count - _Nx <= _Mypair._Myval2._Myres - _Old_size) {
|
||||||
// either we are shrinking, or the growth fits
|
// either we are shrinking, or the growth fits
|
||||||
_Mypair._Myval2._Mysize = _Old_size + _Count - _Nx; // may temporarily overflow;
|
// may temporarily overflow; OK because size_type must be unsigned
|
||||||
// OK because size_type must be unsigned
|
const auto _New_size = _Old_size + _Count - _Nx;
|
||||||
|
_ASAN_STRING_MODIFY(*this, _Old_size, _New_size);
|
||||||
|
_Mypair._Myval2._Mysize = _New_size;
|
||||||
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
|
||||||
_Elem* const _Insert_at = _Old_ptr + _Off;
|
_Elem* const _Insert_at = _Old_ptr + _Off;
|
||||||
_Traits::move(_Insert_at + _Count, _Insert_at + _Nx, _Old_size - _Nx - _Off + 1);
|
_Traits::move(_Insert_at + _Count, _Insert_at + _Nx, _Old_size - _Nx - _Off + 1);
|
||||||
|
@ -4179,7 +4099,7 @@ public:
|
||||||
_CONSTEXPR20 void push_back(const _Elem _Ch) { // insert element at end
|
_CONSTEXPR20 void push_back(const _Elem _Ch) { // insert element at end
|
||||||
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
const size_type _Old_size = _Mypair._Myval2._Mysize;
|
||||||
if (_Old_size < _Mypair._Myval2._Myres) {
|
if (_Old_size < _Mypair._Myval2._Myres) {
|
||||||
_ASAN_STRING_MODIFY(1);
|
_ASAN_STRING_MODIFY(*this, _Old_size, _Old_size + 1);
|
||||||
_Mypair._Myval2._Mysize = _Old_size + 1;
|
_Mypair._Myval2._Mysize = _Old_size + 1;
|
||||||
_Elem* const _Ptr = _Mypair._Myval2._Myptr();
|
_Elem* const _Ptr = _Mypair._Myval2._Myptr();
|
||||||
_Traits::assign(_Ptr[_Old_size], _Ch);
|
_Traits::assign(_Ptr[_Old_size], _Ch);
|
||||||
|
@ -4385,8 +4305,10 @@ public:
|
||||||
// exchange a string in large mode with one in small mode
|
// exchange a string in large mode with one in small mode
|
||||||
const pointer _Ptr = _Starts_large._Bx._Ptr;
|
const pointer _Ptr = _Starts_large._Bx._Ptr;
|
||||||
_Destroy_in_place(_Starts_large._Bx._Ptr);
|
_Destroy_in_place(_Starts_large._Bx._Ptr);
|
||||||
|
|
||||||
_Starts_large._Activate_SSO_buffer();
|
_Starts_large._Activate_SSO_buffer();
|
||||||
_Traits::copy(_Starts_large._Bx._Buf, _Starts_small._Bx._Buf, _BUF_SIZE);
|
_Traits::copy(_Starts_large._Bx._Buf, _Starts_small._Bx._Buf, _BUF_SIZE);
|
||||||
|
|
||||||
_Construct_in_place(_Starts_small._Bx._Ptr, _Ptr);
|
_Construct_in_place(_Starts_small._Bx._Ptr, _Ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4396,19 +4318,8 @@ public:
|
||||||
|
|
||||||
const bool _My_large = _My_data._Large_string_engaged();
|
const bool _My_large = _My_data._Large_string_engaged();
|
||||||
const bool _Right_large = _Right_data._Large_string_engaged();
|
const bool _Right_large = _Right_data._Large_string_engaged();
|
||||||
#ifdef _INSERT_STRING_ANNOTATION
|
|
||||||
if (_My_large && _Right_large) {
|
|
||||||
// nothing
|
|
||||||
} else if (_My_large) {
|
|
||||||
_ASAN_STRING_REMOVE(_Right);
|
|
||||||
} else if (_Right_large) {
|
|
||||||
_ASAN_STRING_REMOVE(*this);
|
|
||||||
} else {
|
|
||||||
_ASAN_STRING_REMOVE(_Right);
|
|
||||||
_ASAN_STRING_REMOVE(*this);
|
|
||||||
}
|
|
||||||
#endif // _INSERT_STRING_ANNOTATION
|
|
||||||
|
|
||||||
|
#if !defined(_INSERT_STRING_ANNOTATION)
|
||||||
if constexpr (_Can_memcpy_val) {
|
if constexpr (_Can_memcpy_val) {
|
||||||
#if _HAS_CXX20
|
#if _HAS_CXX20
|
||||||
if (!_STD is_constant_evaluated())
|
if (!_STD is_constant_evaluated())
|
||||||
|
@ -4423,38 +4334,22 @@ public:
|
||||||
_CSTD memcpy(_My_data_mem, _Right_data_mem, _Memcpy_val_size);
|
_CSTD memcpy(_My_data_mem, _Right_data_mem, _Memcpy_val_size);
|
||||||
_CSTD memcpy(_Right_data_mem, _Temp_mem, _Memcpy_val_size);
|
_CSTD memcpy(_Right_data_mem, _Temp_mem, _Memcpy_val_size);
|
||||||
|
|
||||||
#ifdef _INSERT_STRING_ANNOTATION
|
|
||||||
if (_My_large && _Right_large) {
|
|
||||||
// nothing
|
|
||||||
} else if (_My_large) {
|
|
||||||
_ASAN_STRING_CREATE(*this);
|
|
||||||
} else if (_Right_large) {
|
|
||||||
_ASAN_STRING_CREATE(_Right);
|
|
||||||
} else {
|
|
||||||
_ASAN_STRING_CREATE(_Right);
|
|
||||||
_ASAN_STRING_CREATE(*this);
|
|
||||||
}
|
|
||||||
#endif // _INSERT_STRING_ANNOTATION
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !defined(_INSERT_STRING_ANNOTATION)
|
||||||
|
|
||||||
if (_My_large && _Right_large) { // swap buffers, iterators preserved
|
if (_My_large && _Right_large) { // swap buffers, iterators preserved
|
||||||
_Swap_adl(_My_data._Bx._Ptr, _Right_data._Bx._Ptr);
|
_Swap_adl(_My_data._Bx._Ptr, _Right_data._Bx._Ptr);
|
||||||
} else if (_My_large) { // swap large with small
|
} else if (_My_large) { // swap large with small
|
||||||
_Swap_bx_large_with_small(_My_data, _Right_data);
|
_Swap_bx_large_with_small(_My_data, _Right_data);
|
||||||
_ASAN_STRING_CREATE(*this);
|
|
||||||
} else if (_Right_large) { // swap small with large
|
} else if (_Right_large) { // swap small with large
|
||||||
_Swap_bx_large_with_small(_Right_data, _My_data);
|
_Swap_bx_large_with_small(_Right_data, _My_data);
|
||||||
_ASAN_STRING_CREATE(_Right);
|
|
||||||
} else {
|
} else {
|
||||||
_Elem _Temp_buf[_BUF_SIZE];
|
_Elem _Temp_buf[_BUF_SIZE];
|
||||||
_Traits::copy(_Temp_buf, _My_data._Bx._Buf, _My_data._Mysize + 1);
|
_Traits::copy(_Temp_buf, _My_data._Bx._Buf, _My_data._Mysize + 1);
|
||||||
_Traits::copy(_My_data._Bx._Buf, _Right_data._Bx._Buf, _Right_data._Mysize + 1);
|
_Traits::copy(_My_data._Bx._Buf, _Right_data._Bx._Buf, _Right_data._Mysize + 1);
|
||||||
_Traits::copy(_Right_data._Bx._Buf, _Temp_buf, _My_data._Mysize + 1);
|
_Traits::copy(_Right_data._Bx._Buf, _Temp_buf, _My_data._Mysize + 1);
|
||||||
_ASAN_STRING_CREATE(_Right);
|
|
||||||
_ASAN_STRING_CREATE(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_STD swap(_My_data._Mysize, _Right_data._Mysize);
|
_STD swap(_My_data._Mysize, _Right_data._Mysize);
|
||||||
|
@ -4584,7 +4479,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
_NODISCARD _CONSTEXPR20 size_type find_first_of(
|
_NODISCARD _CONSTEXPR20 size_type find_first_of(
|
||||||
_In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const noexcept /* strengthened */ {
|
_In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const noexcept
|
||||||
|
/* strengthened */ {
|
||||||
// look for one of [_Ptr, <null>) at or after _Off
|
// look for one of [_Ptr, <null>) at or after _Off
|
||||||
return static_cast<size_type>(_Traits_find_first_of<_Traits>(
|
return static_cast<size_type>(_Traits_find_first_of<_Traits>(
|
||||||
_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Traits::length(_Ptr)));
|
_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Traits::length(_Ptr)));
|
||||||
|
@ -4659,7 +4555,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
_NODISCARD _CONSTEXPR20 size_type find_first_not_of(
|
_NODISCARD _CONSTEXPR20 size_type find_first_not_of(
|
||||||
_In_z_ const _Elem* const _Ptr, size_type _Off = 0) const noexcept /* strengthened */ {
|
_In_z_ const _Elem* const _Ptr, size_type _Off = 0) const noexcept
|
||||||
|
/* strengthened */ {
|
||||||
// look for one of [_Ptr, <null>) at or after _Off
|
// look for one of [_Ptr, <null>) at or after _Off
|
||||||
return static_cast<size_type>(_Traits_find_first_not_of<_Traits>(
|
return static_cast<size_type>(_Traits_find_first_not_of<_Traits>(
|
||||||
_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Traits::length(_Ptr)));
|
_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Traits::length(_Ptr)));
|
||||||
|
@ -4971,15 +4868,15 @@ private:
|
||||||
_Traits::copy(_My_data._Bx._Buf, _Unfancy(_Ptr), _My_data._Mysize + 1);
|
_Traits::copy(_My_data._Bx._Buf, _Unfancy(_Ptr), _My_data._Mysize + 1);
|
||||||
_Al.deallocate(_Ptr, _My_data._Myres + 1);
|
_Al.deallocate(_Ptr, _My_data._Myres + 1);
|
||||||
_My_data._Myres = _BUF_SIZE - 1;
|
_My_data._Myres = _BUF_SIZE - 1;
|
||||||
_ASAN_STRING_CREATE(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_CONSTEXPR20 void _Eos(const size_type _New_size) { // set new length and null terminator
|
_CONSTEXPR20 void _Eos(const size_type _New_size) { // set new length and null terminator
|
||||||
_ASAN_STRING_MODIFY(static_cast<difference_type>(_New_size - _Mypair._Myval2._Mysize));
|
_ASAN_STRING_MODIFY(*this, _Mypair._Myval2._Mysize, _New_size);
|
||||||
_Traits::assign(_Mypair._Myval2._Myptr()[_Mypair._Myval2._Mysize = _New_size], _Elem());
|
_Traits::assign(_Mypair._Myval2._Myptr()[_Mypair._Myval2._Mysize = _New_size], _Elem());
|
||||||
}
|
}
|
||||||
|
|
||||||
_CONSTEXPR20 void _Tidy_init() noexcept { // initialize basic_string data members
|
_CONSTEXPR20 void _Tidy_init() noexcept {
|
||||||
|
// initialize basic_string data members
|
||||||
auto& _My_data = _Mypair._Myval2;
|
auto& _My_data = _Mypair._Myval2;
|
||||||
_My_data._Mysize = 0;
|
_My_data._Mysize = 0;
|
||||||
_My_data._Myres = _BUF_SIZE - 1;
|
_My_data._Myres = _BUF_SIZE - 1;
|
||||||
|
@ -4987,14 +4884,13 @@ private:
|
||||||
|
|
||||||
// the _Traits::assign is last so the codegen doesn't think the char write can alias this
|
// the _Traits::assign is last so the codegen doesn't think the char write can alias this
|
||||||
_Traits::assign(_My_data._Bx._Buf[0], _Elem());
|
_Traits::assign(_My_data._Bx._Buf[0], _Elem());
|
||||||
_ASAN_STRING_CREATE(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_CONSTEXPR20 void _Tidy_deallocate() noexcept { // initialize buffer, deallocating any storage
|
_CONSTEXPR20 void _Tidy_deallocate() noexcept { // initialize buffer, deallocating any storage
|
||||||
auto& _My_data = _Mypair._Myval2;
|
auto& _My_data = _Mypair._Myval2;
|
||||||
_My_data._Orphan_all();
|
_My_data._Orphan_all();
|
||||||
_ASAN_STRING_REMOVE(*this);
|
|
||||||
if (_My_data._Large_string_engaged()) {
|
if (_My_data._Large_string_engaged()) {
|
||||||
|
_ASAN_STRING_REMOVE(*this);
|
||||||
const pointer _Ptr = _My_data._Bx._Ptr;
|
const pointer _Ptr = _My_data._Bx._Ptr;
|
||||||
auto& _Al = _Getal();
|
auto& _Al = _Getal();
|
||||||
_Destroy_in_place(_My_data._Bx._Ptr);
|
_Destroy_in_place(_My_data._Bx._Ptr);
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# 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.
|
# 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.
|
# TRANSITION, VSO-1350252 - due to vcasan.lib including the standard library, we can't use it (pending 17.5 preview 2).
|
||||||
# clang-cl does not currently support targeting /MDd or /MTd.
|
# TRANSITION, google/sanitizers#328 - clang-cl does not currently support targeting /MDd or /MTd.
|
||||||
RUNALL_INCLUDE ..\prefix.lst
|
RUNALL_INCLUDE ..\prefix.lst
|
||||||
RUNALL_CROSSLIST
|
RUNALL_CROSSLIST
|
||||||
PM_CL="/Zi /wd4611 /w14640 /Zc:threadSafeInit-" PM_LINK="/debug"
|
PM_CL="/Zi /wd4611 /w14640 /Zc:threadSafeInit-" PM_LINK="/debug"
|
||||||
|
@ -56,8 +56,7 @@ PM_CL="/D_ANNOTATE_STRING /EHsc /MTd /std:c++latest /permissive- /fno-sanitize-a
|
||||||
PM_CL="/D_ANNOTATE_STRING /Za /EHsc /MD /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
PM_CL="/D_ANNOTATE_STRING /Za /EHsc /MD /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
||||||
PM_CL="/D_ANNOTATE_STRING /Za /EHsc /MDd /std:c++latest /permissive- /fno-sanitize-address-vcasan-lib"
|
PM_CL="/D_ANNOTATE_STRING /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_STRING without -fsanitize=address
|
# TRANSITION, clang-cl does not support /alternatename so we cannot test /D_ANNOTATE_STRING without -fsanitize=address
|
||||||
# TRANSITION, VSO-1586016: String annotations disabled temporarily. clang-cl fails to link with empty main.
|
PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MD /std:c++14"
|
||||||
# PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MD /std:c++14"
|
PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MD /std:c++17"
|
||||||
# PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MD /std:c++17"
|
PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MT /std:c++20 /permissive-"
|
||||||
# PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MT /std:c++latest /permissive-"
|
PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MT /std:c++latest /permissive- /fp:strict"
|
||||||
# PM_COMPILER="clang-cl" PM_CL="-fsanitize=address -fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MT /std:c++latest /permissive- /D_HAS_CXX23 /fp:strict"
|
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
// REQUIRES: asan, x64 || x86
|
// REQUIRES: x64 || x86
|
||||||
|
|
||||||
#if 0 // TRANSITION, VSO-1586016: String annotations disabled temporarily.
|
|
||||||
#pragma warning(disable : 4389) // signed/unsigned mismatch in arithmetic
|
|
||||||
#pragma warning(disable : 4984) // 'if constexpr' is a C++17 language extension
|
#pragma warning(disable : 4984) // 'if constexpr' is a C++17 language extension
|
||||||
#pragma warning(disable : 6326) // Potential comparison of a constant with another constant.
|
#pragma warning(disable : 4324) // '%s': structure was padded due to alignment specifier
|
||||||
|
#pragma warning(disable : 4365) // '%s': conversion from '%s' to '%s', signed/unsigned mismatch
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic ignored "-Wsign-compare"
|
|
||||||
#pragma clang diagnostic ignored "-Wc++17-extensions" // constexpr if is a C++17 extension
|
#pragma clang diagnostic ignored "-Wc++17-extensions" // constexpr if is a C++17 extension
|
||||||
#endif // __clang__
|
#endif // __clang__
|
||||||
|
|
||||||
|
@ -30,6 +28,8 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
|
||||||
|
|
||||||
#ifdef __SANITIZE_ADDRESS__
|
#ifdef __SANITIZE_ADDRESS__
|
||||||
extern "C" int __sanitizer_verify_contiguous_container(const void* beg, const void* mid, const void* end) noexcept;
|
extern "C" int __sanitizer_verify_contiguous_container(const void* beg, const void* mid, const void* end) noexcept;
|
||||||
#endif // ASan instrumentation enabled
|
#endif // ASan instrumentation enabled
|
||||||
|
@ -76,6 +76,9 @@ constexpr auto get_sso_input() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class CharType>
|
||||||
|
constexpr size_t max_sso_size = (16 / sizeof(CharType) < 1 ? 1 : 16 / sizeof(CharType)) - 1;
|
||||||
|
|
||||||
#if _HAS_CXX17
|
#if _HAS_CXX17
|
||||||
template <class CharType>
|
template <class CharType>
|
||||||
constexpr auto get_large_input_view() {
|
constexpr auto get_large_input_view() {
|
||||||
|
@ -108,7 +111,7 @@ template <class CharType>
|
||||||
struct throw_on_conversion {
|
struct throw_on_conversion {
|
||||||
throw_on_conversion() = default;
|
throw_on_conversion() = default;
|
||||||
throw_on_conversion(CharType) {}
|
throw_on_conversion(CharType) {}
|
||||||
operator const CharType() const {
|
operator CharType() const {
|
||||||
throw 42;
|
throw 42;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -170,29 +173,30 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class CharType, class Alloc>
|
template <class CharType, class Alloc>
|
||||||
bool verify_string(basic_string<CharType, char_traits<CharType>, Alloc>& str) {
|
bool verify_string(const basic_string<CharType, char_traits<CharType>, Alloc>& str) {
|
||||||
#ifdef __SANITIZE_ADDRESS__
|
#ifdef __SANITIZE_ADDRESS__
|
||||||
constexpr auto proxy_size = _Size_after_ebco_v<_Container_base>;
|
if (str.capacity() == max_sso_size<CharType>) {
|
||||||
if constexpr (proxy_size % _Asan_granularity != 0) { // If we have a misaligned SSO buffer we disable ASAN
|
|
||||||
constexpr size_t max_sso_size = (16 / sizeof(CharType) < 1 ? 1 : 16 / sizeof(CharType)) - 1;
|
|
||||||
if (str.capacity() == max_sso_size) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t buffer_size = (str.capacity() + 1) * sizeof(CharType);
|
|
||||||
void* buffer = const_cast<void*>(static_cast<const void*>(str.data()));
|
|
||||||
void* aligned_start = align(8, 1, buffer, buffer_size);
|
|
||||||
|
|
||||||
if (!aligned_start) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void* end = const_cast<void*>(static_cast<const void*>(str.data() + (str.capacity() + 1)));
|
const void* const buffer = str.data();
|
||||||
const void* mid = const_cast<void*>(static_cast<const void*>(str.data() + str.size() + 1));
|
const void* const buf_end = str.data() + str.capacity() + 1;
|
||||||
const void* aligned_mid = mid > aligned_start ? mid : aligned_start;
|
|
||||||
|
|
||||||
return __sanitizer_verify_contiguous_container(aligned_start, aligned_mid, end) != 0;
|
constexpr bool _Large_string_always_aligned =
|
||||||
|
(_Container_allocation_minimum_asan_alignment<decay_t<decltype(str)>>) >= 8;
|
||||||
|
|
||||||
|
_Asan_aligned_pointers aligned;
|
||||||
|
if constexpr (_Large_string_always_aligned) {
|
||||||
|
aligned = {buffer, _Get_asan_aligned_after(buf_end)};
|
||||||
|
} else {
|
||||||
|
aligned = _Get_asan_aligned_first_end(buffer, buf_end);
|
||||||
|
}
|
||||||
|
assert(aligned._First != aligned._End);
|
||||||
|
|
||||||
|
const void* const mid = str.data() + str.size() + 1;
|
||||||
|
const void* const fixed_mid = aligned._Clamp_to_end(mid);
|
||||||
|
|
||||||
|
return __sanitizer_verify_contiguous_container(aligned._First, fixed_mid, aligned._End) != 0;
|
||||||
#else // ^^^ ASan instrumentation enabled / ASan instrumentation disabled vvv
|
#else // ^^^ ASan instrumentation enabled / ASan instrumentation disabled vvv
|
||||||
(void) str;
|
(void) str;
|
||||||
return true;
|
return true;
|
||||||
|
@ -221,7 +225,7 @@ constexpr bool operator!=(
|
||||||
|
|
||||||
template <class CharType, class Pocma = true_type, class Stateless = true_type>
|
template <class CharType, class Pocma = true_type, class Stateless = true_type>
|
||||||
struct aligned_allocator : public custom_test_allocator<CharType, Pocma, Stateless> {
|
struct aligned_allocator : public custom_test_allocator<CharType, Pocma, Stateless> {
|
||||||
static constexpr size_t _Minimum_allocation_alignment = 8;
|
static constexpr size_t _Minimum_asan_allocation_alignment = 8;
|
||||||
|
|
||||||
aligned_allocator() = default;
|
aligned_allocator() = default;
|
||||||
template <class U>
|
template <class U>
|
||||||
|
@ -235,10 +239,15 @@ struct aligned_allocator : public custom_test_allocator<CharType, Pocma, Statele
|
||||||
delete[] p;
|
delete[] p;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
STATIC_ASSERT(
|
||||||
|
_Container_allocation_minimum_asan_alignment<basic_string<char, char_traits<char>, aligned_allocator<char>>> == 8);
|
||||||
|
STATIC_ASSERT(_Container_allocation_minimum_asan_alignment<
|
||||||
|
basic_string<wchar_t, char_traits<wchar_t>, aligned_allocator<wchar_t>>>
|
||||||
|
== 8);
|
||||||
|
|
||||||
template <class CharType, class Pocma = true_type, class Stateless = true_type>
|
template <class CharType, class Pocma = true_type, class Stateless = true_type>
|
||||||
struct explicit_allocator : public custom_test_allocator<CharType, Pocma, Stateless> {
|
struct explicit_allocator : public custom_test_allocator<CharType, Pocma, Stateless> {
|
||||||
static constexpr size_t _Minimum_allocation_alignment = alignof(CharType);
|
static constexpr size_t _Minimum_asan_allocation_alignment = alignof(CharType);
|
||||||
|
|
||||||
explicit_allocator() = default;
|
explicit_allocator() = default;
|
||||||
template <class U>
|
template <class U>
|
||||||
|
@ -253,6 +262,11 @@ struct explicit_allocator : public custom_test_allocator<CharType, Pocma, Statel
|
||||||
delete[] (p - 1);
|
delete[] (p - 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
STATIC_ASSERT(
|
||||||
|
_Container_allocation_minimum_asan_alignment<basic_string<char, char_traits<char>, explicit_allocator<char>>> == 1);
|
||||||
|
STATIC_ASSERT(_Container_allocation_minimum_asan_alignment<
|
||||||
|
basic_string<wchar_t, char_traits<wchar_t>, explicit_allocator<wchar_t>>>
|
||||||
|
== 2);
|
||||||
|
|
||||||
template <class CharType, class Pocma = true_type, class Stateless = true_type>
|
template <class CharType, class Pocma = true_type, class Stateless = true_type>
|
||||||
struct implicit_allocator : public custom_test_allocator<CharType, Pocma, Stateless> {
|
struct implicit_allocator : public custom_test_allocator<CharType, Pocma, Stateless> {
|
||||||
|
@ -269,6 +283,11 @@ struct implicit_allocator : public custom_test_allocator<CharType, Pocma, Statel
|
||||||
delete[] (p - 1);
|
delete[] (p - 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
STATIC_ASSERT(
|
||||||
|
_Container_allocation_minimum_asan_alignment<basic_string<char, char_traits<char>, implicit_allocator<char>>> == 1);
|
||||||
|
STATIC_ASSERT(_Container_allocation_minimum_asan_alignment<
|
||||||
|
basic_string<wchar_t, char_traits<wchar_t>, implicit_allocator<wchar_t>>>
|
||||||
|
== 2);
|
||||||
|
|
||||||
template <class Alloc>
|
template <class Alloc>
|
||||||
void test_construction() {
|
void test_construction() {
|
||||||
|
@ -276,12 +295,12 @@ void test_construction() {
|
||||||
using str = basic_string<CharType, char_traits<CharType>, Alloc>;
|
using str = basic_string<CharType, char_traits<CharType>, Alloc>;
|
||||||
{ // constructors
|
{ // constructors
|
||||||
// range constructors
|
// range constructors
|
||||||
str literal_constructed{get_large_input<CharType>()};
|
|
||||||
assert(verify_string(literal_constructed));
|
|
||||||
|
|
||||||
str literal_constructed_sso{get_sso_input<CharType>()};
|
str literal_constructed_sso{get_sso_input<CharType>()};
|
||||||
assert(verify_string(literal_constructed_sso));
|
assert(verify_string(literal_constructed_sso));
|
||||||
|
|
||||||
|
str literal_constructed{get_large_input<CharType>()};
|
||||||
|
assert(verify_string(literal_constructed));
|
||||||
|
|
||||||
str initializer_list_constructed({CharType{'H'}, CharType{'e'}, CharType{'l'}, CharType{'l'}, CharType{'o'},
|
str initializer_list_constructed({CharType{'H'}, CharType{'e'}, CharType{'l'}, CharType{'l'}, CharType{'o'},
|
||||||
CharType{' '}, //
|
CharType{' '}, //
|
||||||
CharType{'f'}, CharType{'l'}, CharType{'u'}, CharType{'f'}, CharType{'f'}, CharType{'y'}, CharType{' '},
|
CharType{'f'}, CharType{'l'}, CharType{'u'}, CharType{'f'}, CharType{'f'}, CharType{'y'}, CharType{' '},
|
||||||
|
@ -530,11 +549,10 @@ void test_append() {
|
||||||
|
|
||||||
constexpr size_t large_size = 20;
|
constexpr size_t large_size = 20;
|
||||||
constexpr size_t sso_size = 1;
|
constexpr size_t sso_size = 1;
|
||||||
constexpr size_t max_sso_size = (16 / sizeof(CharType) < 1 ? 1 : 16 / sizeof(CharType)) - 1;
|
|
||||||
|
|
||||||
const str input(large_size, CharType{'b'});
|
const str input(large_size, CharType{'b'});
|
||||||
const str input_sso(sso_size, CharType{'b'});
|
const str input_sso(sso_size, CharType{'b'});
|
||||||
const str input_sso_growing(max_sso_size, CharType{'b'});
|
const str input_sso_growing(max_sso_size<CharType>, CharType{'b'});
|
||||||
|
|
||||||
{ // push_back
|
{ // push_back
|
||||||
str push_back{input};
|
str push_back{input};
|
||||||
|
@ -851,7 +869,7 @@ void test_append() {
|
||||||
str op_rstr_char_sso = str(sso_size, CharType{'b'}) + CharType{'!'};
|
str op_rstr_char_sso = str(sso_size, CharType{'b'}) + CharType{'!'};
|
||||||
assert(verify_string(op_rstr_char_sso));
|
assert(verify_string(op_rstr_char_sso));
|
||||||
|
|
||||||
str op_rstr_char_sso_growing = str(max_sso_size, CharType{'b'}) + CharType{'!'};
|
str op_rstr_char_sso_growing = str(max_sso_size<CharType>, CharType{'b'}) + CharType{'!'};
|
||||||
assert(verify_string(op_rstr_char_sso_growing));
|
assert(verify_string(op_rstr_char_sso_growing));
|
||||||
|
|
||||||
str op_char_rstr_large = CharType{'!'} + str(large_size, CharType{'b'});
|
str op_char_rstr_large = CharType{'!'} + str(large_size, CharType{'b'});
|
||||||
|
@ -860,7 +878,7 @@ void test_append() {
|
||||||
str op_char_rstr_sso = CharType{'!'} + str(sso_size, CharType{'b'});
|
str op_char_rstr_sso = CharType{'!'} + str(sso_size, CharType{'b'});
|
||||||
assert(verify_string(op_char_rstr_sso));
|
assert(verify_string(op_char_rstr_sso));
|
||||||
|
|
||||||
str op_char_rstr_sso_growing = CharType{'!'} + str(max_sso_size, CharType{'b'});
|
str op_char_rstr_sso_growing = CharType{'!'} + str(max_sso_size<CharType>, CharType{'b'});
|
||||||
assert(verify_string(op_char_rstr_sso_growing));
|
assert(verify_string(op_char_rstr_sso_growing));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1203,11 +1221,10 @@ void test_insertion() {
|
||||||
|
|
||||||
constexpr size_t large_size = 20;
|
constexpr size_t large_size = 20;
|
||||||
constexpr size_t sso_size = 1;
|
constexpr size_t sso_size = 1;
|
||||||
constexpr size_t max_sso_size = (16 / sizeof(CharType) < 1 ? 1 : 16 / sizeof(CharType)) - 1;
|
|
||||||
|
|
||||||
const str input(large_size, CharType{'b'});
|
const str input(large_size, CharType{'b'});
|
||||||
const str input_sso(sso_size, CharType{'b'});
|
const str input_sso(sso_size, CharType{'b'});
|
||||||
const str input_sso_growing(max_sso_size, CharType{'b'});
|
const str input_sso_growing(max_sso_size<CharType>, CharType{'b'});
|
||||||
|
|
||||||
input_iterator_tester<CharType, 3> input_iter_data_sso;
|
input_iterator_tester<CharType, 3> input_iter_data_sso;
|
||||||
|
|
||||||
|
@ -1581,6 +1598,49 @@ void test_misc() {
|
||||||
assert(verify_string(resize_char_sso_to_sso));
|
assert(verify_string(resize_char_sso_to_sso));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // replace
|
||||||
|
const CharType mrow[] = {'m', 'r', 'o', 'w', '\0'};
|
||||||
|
|
||||||
|
str replace_front_bigger{input};
|
||||||
|
replace_front_bigger.replace(0, 2, mrow);
|
||||||
|
assert(verify_string(replace_front_bigger));
|
||||||
|
str replace_front_same{input};
|
||||||
|
replace_front_same.replace(0, 4, mrow);
|
||||||
|
assert(verify_string(replace_front_same));
|
||||||
|
str replace_front_smaller{input};
|
||||||
|
replace_front_smaller.replace(0, 6, mrow);
|
||||||
|
assert(verify_string(replace_front_smaller));
|
||||||
|
|
||||||
|
str replace_mid_bigger{input};
|
||||||
|
replace_mid_bigger.replace(2, 2, mrow);
|
||||||
|
assert(verify_string(replace_mid_bigger));
|
||||||
|
str replace_mid_same{input};
|
||||||
|
replace_mid_same.replace(2, 4, mrow);
|
||||||
|
assert(verify_string(replace_mid_same));
|
||||||
|
str replace_mid_smaller{input};
|
||||||
|
replace_mid_smaller.replace(2, 6, mrow);
|
||||||
|
assert(verify_string(replace_mid_smaller));
|
||||||
|
|
||||||
|
str replace_back_bigger{input};
|
||||||
|
replace_back_bigger.replace(replace_back_bigger.size() - 2, 2, mrow);
|
||||||
|
assert(verify_string(replace_back_bigger));
|
||||||
|
str replace_back_same{input};
|
||||||
|
replace_back_same.replace(replace_back_same.size() - 4, 4, mrow);
|
||||||
|
assert(verify_string(replace_back_same));
|
||||||
|
str replace_back_smaller{input};
|
||||||
|
replace_back_smaller.replace(replace_back_smaller.size() - 6, 6, mrow);
|
||||||
|
assert(verify_string(replace_back_smaller));
|
||||||
|
|
||||||
|
const CharType hi[] = {'h', 'i', '\0'};
|
||||||
|
str replace_large_to_sso{input};
|
||||||
|
replace_large_to_sso.replace(0, replace_large_to_sso.size() - 1, hi);
|
||||||
|
assert(verify_string(replace_large_to_sso));
|
||||||
|
|
||||||
|
str replace_sso_to_large{input_sso};
|
||||||
|
replace_sso_to_large.replace(0, 1, input);
|
||||||
|
assert(verify_string(replace_sso_to_large));
|
||||||
|
}
|
||||||
|
|
||||||
if constexpr (allocator_traits<Alloc>::propagate_on_container_swap::value) { // swap
|
if constexpr (allocator_traits<Alloc>::propagate_on_container_swap::value) { // swap
|
||||||
str first_large{input};
|
str first_large{input};
|
||||||
str second_large = input + str{CharType{'c'}, CharType{'a'}, CharType{'t'}};
|
str second_large = input + str{CharType{'c'}, CharType{'a'}, CharType{'t'}};
|
||||||
|
@ -1845,6 +1905,14 @@ void test_DevCom_10116361() {
|
||||||
s1.~string();
|
s1.~string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_DevCom_10109507() {
|
||||||
|
// replace failed to correctly munge asan annotations while working
|
||||||
|
string s("abcd");
|
||||||
|
s.replace(0, 1, "ef", 2);
|
||||||
|
s.replace(0, 0, "xy", 2);
|
||||||
|
assert(s == "xyefbcd");
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
run_allocator_matrix<char>();
|
run_allocator_matrix<char>();
|
||||||
#ifdef __cpp_char8_t
|
#ifdef __cpp_char8_t
|
||||||
|
@ -1855,7 +1923,5 @@ int main() {
|
||||||
run_allocator_matrix<wchar_t>();
|
run_allocator_matrix<wchar_t>();
|
||||||
|
|
||||||
test_DevCom_10116361();
|
test_DevCom_10116361();
|
||||||
|
test_DevCom_10109507();
|
||||||
}
|
}
|
||||||
#endif // TRANSITION, VSO-1586016
|
|
||||||
|
|
||||||
int main() {}
|
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# 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.
|
# 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.
|
# TRANSITION, VSO-1350252 - due to vcasan.lib including the standard library, we can't use it (pending 17.5 preview 2).
|
||||||
# clang-cl does not currently support targeting /MDd or /MTd.
|
# TRANSITION, google/sanitizers#328 - clang-cl does not currently support targeting /MDd or /MTd.
|
||||||
RUNALL_INCLUDE ..\prefix.lst
|
RUNALL_INCLUDE ..\prefix.lst
|
||||||
RUNALL_CROSSLIST
|
RUNALL_CROSSLIST
|
||||||
PM_CL="/Zi /wd4611 /w14640 /Zc:threadSafeInit-" PM_LINK="/debug"
|
PM_CL="/Zi /wd4611 /w14640 /Zc:threadSafeInit-" PM_LINK="/debug"
|
||||||
|
|
|
@ -12,8 +12,16 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#pragma warning(disable : 4984) // 'if constexpr' is a C++17 language extension
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic ignored "-Wc++17-extensions" // constexpr if is a C++17 extension
|
||||||
|
#endif // __clang__
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
|
||||||
|
|
||||||
#ifndef __SANITIZE_ADDRESS__
|
#ifndef __SANITIZE_ADDRESS__
|
||||||
#if defined(__clang__) && defined(__has_feature)
|
#if defined(__clang__) && defined(__has_feature)
|
||||||
#if __has_feature(address_sanitizer)
|
#if __has_feature(address_sanitizer)
|
||||||
|
@ -148,19 +156,23 @@ public:
|
||||||
template <class T, class Alloc>
|
template <class T, class Alloc>
|
||||||
bool verify_vector(vector<T, Alloc>& vec) {
|
bool verify_vector(vector<T, Alloc>& vec) {
|
||||||
#ifdef __SANITIZE_ADDRESS__
|
#ifdef __SANITIZE_ADDRESS__
|
||||||
size_t buffer_bytes = vec.capacity() * sizeof(T);
|
const void* buffer = vec.data();
|
||||||
void* buffer = vec.data();
|
const void* buf_end = vec.data() + vec.capacity();
|
||||||
void* aligned_start = align(8, 1, buffer, buffer_bytes);
|
_Asan_aligned_pointers aligned;
|
||||||
|
|
||||||
if (!aligned_start) {
|
if constexpr ((_Container_allocation_minimum_asan_alignment<vector<T, Alloc>>) >= 8) {
|
||||||
|
aligned = {buffer, buf_end};
|
||||||
|
} else {
|
||||||
|
aligned = _Get_asan_aligned_first_end(buffer, buf_end);
|
||||||
|
if (aligned._First == aligned._End) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void* mid = vec.data() + vec.size();
|
const void* const mid = vec.data() + vec.size();
|
||||||
mid = mid > aligned_start ? mid : aligned_start;
|
const void* const fixed_mid = aligned._Clamp_to_end(mid);
|
||||||
|
|
||||||
void* bad_address =
|
void* bad_address = __sanitizer_contiguous_container_find_bad_address(aligned._First, fixed_mid, aligned._End);
|
||||||
__sanitizer_contiguous_container_find_bad_address(aligned_start, mid, vec.data() + vec.capacity());
|
|
||||||
if (bad_address == nullptr) {
|
if (bad_address == nullptr) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -172,9 +184,11 @@ bool verify_vector(vector<T, Alloc>& vec) {
|
||||||
}
|
}
|
||||||
cout << "Vector State:" << endl;
|
cout << "Vector State:" << endl;
|
||||||
cout << " begin: " << buffer << endl;
|
cout << " begin: " << buffer << endl;
|
||||||
cout << " aligned begin: " << aligned_start << endl;
|
cout << " aligned begin: " << aligned._First << endl;
|
||||||
cout << " last: " << reinterpret_cast<void*>(vec.data() + vec.size()) << endl;
|
cout << " last: " << mid << endl;
|
||||||
cout << " end: " << reinterpret_cast<void*>(vec.data() + vec.capacity()) << endl;
|
cout << " aligned_last: " << fixed_mid << endl;
|
||||||
|
cout << " end: " << buf_end << endl;
|
||||||
|
cout << " aligned_end: " << aligned._End << endl;
|
||||||
__asan_describe_address(bad_address);
|
__asan_describe_address(bad_address);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -206,7 +220,7 @@ constexpr bool operator!=(
|
||||||
|
|
||||||
template <class T, class Pocma = true_type, class Stateless = true_type>
|
template <class T, class Pocma = true_type, class Stateless = true_type>
|
||||||
struct aligned_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
struct aligned_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
||||||
static constexpr size_t _Minimum_allocation_alignment = 8;
|
static constexpr size_t _Minimum_asan_allocation_alignment = 8;
|
||||||
|
|
||||||
aligned_allocator() = default;
|
aligned_allocator() = default;
|
||||||
template <class U>
|
template <class U>
|
||||||
|
@ -220,10 +234,11 @@ struct aligned_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
||||||
delete[] p;
|
delete[] p;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
STATIC_ASSERT(_Container_allocation_minimum_asan_alignment<vector<char, aligned_allocator<char>>> == 8);
|
||||||
|
|
||||||
template <class T, class Pocma = true_type, class Stateless = true_type>
|
template <class T, class Pocma = true_type, class Stateless = true_type>
|
||||||
struct explicit_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
struct explicit_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
||||||
static constexpr size_t _Minimum_allocation_alignment = alignof(T);
|
static constexpr size_t _Minimum_asan_allocation_alignment = alignof(T);
|
||||||
|
|
||||||
explicit_allocator() = default;
|
explicit_allocator() = default;
|
||||||
template <class U>
|
template <class U>
|
||||||
|
@ -238,6 +253,8 @@ struct explicit_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
||||||
delete[] (p - 1);
|
delete[] (p - 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
STATIC_ASSERT(_Container_allocation_minimum_asan_alignment<vector<char, explicit_allocator<char>>> == 1);
|
||||||
|
STATIC_ASSERT(_Container_allocation_minimum_asan_alignment<vector<wchar_t, explicit_allocator<wchar_t>>> == 2);
|
||||||
|
|
||||||
template <class T, class Pocma = true_type, class Stateless = true_type>
|
template <class T, class Pocma = true_type, class Stateless = true_type>
|
||||||
struct implicit_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
struct implicit_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
||||||
|
@ -254,6 +271,8 @@ struct implicit_allocator : custom_test_allocator<T, Pocma, Stateless> {
|
||||||
delete[] (p - 1);
|
delete[] (p - 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
STATIC_ASSERT(_Container_allocation_minimum_asan_alignment<vector<char, implicit_allocator<char>>> == 1);
|
||||||
|
STATIC_ASSERT(_Container_allocation_minimum_asan_alignment<vector<wchar_t, implicit_allocator<wchar_t>>> == 2);
|
||||||
|
|
||||||
template <class Alloc>
|
template <class Alloc>
|
||||||
void test_push_pop() {
|
void test_push_pop() {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче