Skip to content

Commit

Permalink
[libc++][ASan] Stop optimizations in std::basic_string
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Advenam Tacet committed May 6, 2024
1 parent c9f38d2 commit 0ba0371
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 7 deletions.
46 changes: 40 additions & 6 deletions libcxx/include/string
Original file line number Diff line number Diff line change
Expand Up @@ -735,10 +735,44 @@ public:
//
// This string implementation doesn't contain any references into itself. It only contains a bit that says whether
// it is in small or large string mode, so the entire structure is trivially relocatable if its members are.
#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
// When compiling with AddressSanitizer (ASan), basic_string cannot be trivially
// relocatable. Because the object's memory might be poisoned when its content
// is kept inside objects memory (short string optimization), instead of in allocated
// external memory. In such cases, the destructor is responsible for unpoisoning
// the memory to avoid triggering false positives.
// Therefore it's crucial to ensure the destructor is called
using __trivially_relocatable = false_type;
#else
using __trivially_relocatable = __conditional_t<
__libcpp_is_trivially_relocatable<allocator_type>::value && __libcpp_is_trivially_relocatable<pointer>::value,
basic_string,
void>;
#endif
#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
pointer __asan_volatile_wrapper(pointer const &__ptr) const {
if (__libcpp_is_constant_evaluated())
return __ptr;

pointer volatile __copy_ptr = __ptr;

return const_cast<pointer &>(__copy_ptr);
}

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
const_pointer __asan_volatile_wrapper(const_pointer const &__ptr) const {
if (__libcpp_is_constant_evaluated())
return __ptr;

const_pointer volatile __copy_ptr = __ptr;

return const_cast<const_pointer &>(__copy_ptr);
}
#define _LIBCPP_ASAN_VOLATILE_WRAPPER(PTR) __asan_volatile_wrapper(PTR)
#else
#define _LIBCPP_ASAN_VOLATILE_WRAPPER(PTR) PTR
#endif

static_assert((!is_array<value_type>::value), "Character type of basic_string must not be an array");
static_assert((is_standard_layout<value_type>::value), "Character type of basic_string must be standard-layout");
Expand Down Expand Up @@ -1885,16 +1919,16 @@ private:
__r_.first().__l.__data_ = __p;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_long_pointer() _NOEXCEPT {
return __r_.first().__l.__data_;
return _LIBCPP_ASAN_VOLATILE_WRAPPER(__r_.first().__l.__data_);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_pointer __get_long_pointer() const _NOEXCEPT {
return __r_.first().__l.__data_;
return _LIBCPP_ASAN_VOLATILE_WRAPPER(__r_.first().__l.__data_);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_short_pointer() _NOEXCEPT {
return pointer_traits<pointer>::pointer_to(__r_.first().__s.__data_[0]);
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS pointer __get_short_pointer() _NOEXCEPT {
return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<pointer>::pointer_to(__r_.first().__s.__data_[0]));
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_pointer __get_short_pointer() const _NOEXCEPT {
return pointer_traits<const_pointer>::pointer_to(__r_.first().__s.__data_[0]);
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS const_pointer __get_short_pointer() const _NOEXCEPT {
return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<const_pointer>::pointer_to(__r_.first().__s.__data_[0]));
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_pointer() _NOEXCEPT {
return __is_long() ? __get_long_pointer() : __get_short_pointer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ static_assert(!std::__libcpp_is_trivially_relocatable<MoveOnlyTriviallyCopyable>
// ----------------------

// basic_string
#if defined(_LIBCPP_HAS_NO_ASAN) || !defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
struct MyChar {
char c;
};
Expand Down Expand Up @@ -78,7 +79,7 @@ static_assert(
!std::__libcpp_is_trivially_relocatable<
std::basic_string<MyChar, NotTriviallyRelocatableCharTraits<MyChar>, test_allocator<MyChar> > >::value,
"");

#endif
// unique_ptr
struct NotTriviallyRelocatableDeleter {
NotTriviallyRelocatableDeleter(const NotTriviallyRelocatableDeleter&);
Expand Down

0 comments on commit 0ba0371

Please sign in to comment.