Skip to content

Commit 82abf82

Browse files
author
Advenam Tacet
committed
[libc++][ASan] Stop optimizations in std::basic_string
This commit stops some optimizations when compiling with ASan. - Short strings make std::basic_string to not be trivially relocatable, because memory has to be unpoisoned. It changes value of `__trivially_relocatable` when compiling with ASan. - It truns off compiler stack optimizations with `__asan_volatile_wrapper`, the function is not used when compiling without ASan. - It turns off instrumentation in a few functions.
1 parent c9f38d2 commit 82abf82

File tree

2 files changed

+32
-7
lines changed

2 files changed

+32
-7
lines changed

libcxx/include/string

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -735,10 +735,34 @@ public:
735735
//
736736
// This string implementation doesn't contain any references into itself. It only contains a bit that says whether
737737
// it is in small or large string mode, so the entire structure is trivially relocatable if its members are.
738+
#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
739+
// When compiling with AddressSanitizer (ASan), basic_string cannot be trivially
740+
// relocatable. Because the object's memory might be poisoned when its content
741+
// is kept inside objects memory (short string optimization), instead of in allocated
742+
// external memory. In such cases, the destructor is responsible for unpoisoning
743+
// the memory to avoid triggering false positives.
744+
// Therefore it's crucial to ensure the destructor is called
745+
using __trivially_relocatable = false_type;
746+
#else
738747
using __trivially_relocatable = __conditional_t<
739748
__libcpp_is_trivially_relocatable<allocator_type>::value && __libcpp_is_trivially_relocatable<pointer>::value,
740749
basic_string,
741750
void>;
751+
#endif
752+
template<class PtrT>
753+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
754+
PtrT __asan_volatile_wrapper(PtrT const &__ptr) const {
755+
#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
756+
if (__libcpp_is_constant_evaluated())
757+
return __ptr;
758+
759+
PtrT volatile __copy_ptr = __ptr;
760+
761+
return const_cast<PtrT &>(__copy_ptr);
762+
#else
763+
return __ptr;
764+
#endif
765+
}
742766

743767
static_assert((!is_array<value_type>::value), "Character type of basic_string must not be an array");
744768
static_assert((is_standard_layout<value_type>::value), "Character type of basic_string must be standard-layout");
@@ -1885,16 +1909,16 @@ private:
18851909
__r_.first().__l.__data_ = __p;
18861910
}
18871911
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_long_pointer() _NOEXCEPT {
1888-
return __r_.first().__l.__data_;
1912+
return __asan_volatile_wrapper<pointer>(__r_.first().__l.__data_);
18891913
}
18901914
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_pointer __get_long_pointer() const _NOEXCEPT {
1891-
return __r_.first().__l.__data_;
1915+
return __asan_volatile_wrapper<const_pointer>(__r_.first().__l.__data_);
18921916
}
1893-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_short_pointer() _NOEXCEPT {
1894-
return pointer_traits<pointer>::pointer_to(__r_.first().__s.__data_[0]);
1917+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS pointer __get_short_pointer() _NOEXCEPT {
1918+
return __asan_volatile_wrapper<pointer>(pointer_traits<pointer>::pointer_to(__r_.first().__s.__data_[0]));
18951919
}
1896-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_pointer __get_short_pointer() const _NOEXCEPT {
1897-
return pointer_traits<const_pointer>::pointer_to(__r_.first().__s.__data_[0]);
1920+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS const_pointer __get_short_pointer() const _NOEXCEPT {
1921+
return __asan_volatile_wrapper<const_pointer>(pointer_traits<const_pointer>::pointer_to(__r_.first().__s.__data_[0]));
18981922
}
18991923
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_pointer() _NOEXCEPT {
19001924
return __is_long() ? __get_long_pointer() : __get_short_pointer();

libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ static_assert(!std::__libcpp_is_trivially_relocatable<MoveOnlyTriviallyCopyable>
4848
// ----------------------
4949

5050
// basic_string
51+
#if defined(_LIBCPP_HAS_NO_ASAN) || !defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
5152
struct MyChar {
5253
char c;
5354
};
@@ -78,7 +79,7 @@ static_assert(
7879
!std::__libcpp_is_trivially_relocatable<
7980
std::basic_string<MyChar, NotTriviallyRelocatableCharTraits<MyChar>, test_allocator<MyChar> > >::value,
8081
"");
81-
82+
#endif
8283
// unique_ptr
8384
struct NotTriviallyRelocatableDeleter {
8485
NotTriviallyRelocatableDeleter(const NotTriviallyRelocatableDeleter&);

0 commit comments

Comments
 (0)