-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Revert "[ASan][libc++] Turn on ASan annotations for short strings" #78627
Conversation
@llvm/pr-subscribers-libcxx Author: Vitaly Buka (vitalybuka) ChangesReverts llvm/llvm-project#75882 To recover build bots : Full diff: https://github.com/llvm/llvm-project/pull/78627.diff 5 Files Affected:
diff --git a/libcxx/include/string b/libcxx/include/string
index 4116f350a80476..e97139206d4fa7 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -659,6 +659,7 @@ _LIBCPP_PUSH_MACROS
#else
# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
#endif
+#define _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED false
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -1895,17 +1896,22 @@ private:
#endif
}
+ // ASan: short string is poisoned if and only if this function returns true.
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __asan_short_string_is_annotated() const _NOEXCEPT {
+ return _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED && !__libcpp_is_constant_evaluated();
+ }
+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_new(size_type __current_size) const _NOEXCEPT {
(void) __current_size;
#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
- if (!__libcpp_is_constant_evaluated())
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
__annotate_contiguous_container(data() + capacity() + 1, data() + __current_size + 1);
#endif
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_delete() const _NOEXCEPT {
#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
- if (!__libcpp_is_constant_evaluated())
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
__annotate_contiguous_container(data() + size() + 1, data() + capacity() + 1);
#endif
}
@@ -1913,7 +1919,7 @@ private:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_increase(size_type __n) const _NOEXCEPT {
(void) __n;
#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
- if (!__libcpp_is_constant_evaluated())
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
__annotate_contiguous_container(data() + size() + 1, data() + size() + 1 + __n);
#endif
}
@@ -1921,7 +1927,7 @@ private:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_shrink(size_type __old_size) const _NOEXCEPT {
(void) __old_size;
#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
- if (!__libcpp_is_constant_evaluated())
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
__annotate_contiguous_container(data() + __old_size + 1, data() + size() + 1);
#endif
}
diff --git a/libcxx/test/libcxx/containers/strings/basic.string/asan_deque_integration.pass.cpp b/libcxx/test/libcxx/containers/strings/basic.string/asan_deque_integration.pass.cpp
deleted file mode 100644
index b914609f35ddf3..00000000000000
--- a/libcxx/test/libcxx/containers/strings/basic.string/asan_deque_integration.pass.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// REQUIRES: asan
-// UNSUPPORTED: c++03
-
-#include <cassert>
-#include <string>
-#include <array>
-#include <deque>
-#include "test_macros.h"
-#include "asan_testing.h"
-#include "min_allocator.h"
-
-// This tests exists to check if strings work well with deque, as those
-// may be partialy annotated, we cannot simply call
-// is_double_ended_contiguous_container_asan_correct, as it assumes that
-// object memory inside is not annotated, so we check everything in a more careful way.
-
-template <typename D>
-void verify_inside(D const& d) {
- for (size_t i = 0; i < d.size(); ++i) {
- assert(is_string_asan_correct(d[i]));
- }
-}
-
-template <typename S, size_t N>
-S get_s(char c) {
- S s;
- for (size_t i = 0; i < N; ++i)
- s.push_back(c);
-
- return s;
-}
-
-template <class C, class S>
-void test_string() {
- size_t const N = sizeof(S) < 256 ? (4096 / sizeof(S)) : 16;
-
- {
- C d1a(1), d1b(N), d1c(N + 1), d1d(32 * N);
- verify_inside(d1a);
- verify_inside(d1b);
- verify_inside(d1c);
- verify_inside(d1d);
- }
- {
- C d2;
- for (size_t i = 0; i < 16 * N; ++i) {
- d2.push_back(get_s<S, 1>(i % 10 + 'a'));
- verify_inside(d2);
- d2.push_back(get_s<S, 222>(i % 10 + 'b'));
- verify_inside(d2);
-
- d2.pop_front();
- verify_inside(d2);
- }
- }
- {
- C d3;
- for (size_t i = 0; i < 16 * N; ++i) {
- d3.push_front(get_s<S, 1>(i % 10 + 'a'));
- verify_inside(d3);
- d3.push_front(get_s<S, 222>(i % 10 + 'b'));
- verify_inside(d3);
-
- d3.pop_back();
- verify_inside(d3);
- }
- }
- {
- C d4;
- for (size_t i = 0; i < 16 * N; ++i) {
- // When there is no SSO, all elements inside should not be poisoned,
- // so we can verify deque poisoning.
- d4.push_front(get_s<S, 333>(i % 10 + 'a'));
- verify_inside(d4);
- assert(is_double_ended_contiguous_container_asan_correct(d4));
- d4.push_back(get_s<S, 222>(i % 10 + 'b'));
- verify_inside(d4);
- assert(is_double_ended_contiguous_container_asan_correct(d4));
- }
- }
- {
- C d5;
- for (size_t i = 0; i < 5 * N; ++i) {
- // In d4 we never had poisoned memory inside deque.
- // Here we start with SSO, so part of the inside of the container,
- // will be poisoned.
- d5.push_front(S());
- verify_inside(d5);
- }
- for (size_t i = 0; i < d5.size(); ++i) {
- // We change the size to have long string.
- // Memory owne by deque should not be poisoned by string.
- d5[i].resize(1000);
- verify_inside(d5);
- }
-
- assert(is_double_ended_contiguous_container_asan_correct(d5));
-
- d5.erase(d5.begin() + 2);
- verify_inside(d5);
-
- d5.erase(d5.end() - 2);
- verify_inside(d5);
-
- assert(is_double_ended_contiguous_container_asan_correct(d5));
- }
- {
- C d6a;
- assert(is_double_ended_contiguous_container_asan_correct(d6a));
-
- C d6b(N + 2, get_s<S, 1000>('a'));
- d6b.push_front(get_s<S, 1001>('b'));
- while (!d6b.empty()) {
- d6b.pop_back();
- assert(is_double_ended_contiguous_container_asan_correct(d6b));
- }
-
- C d6c(N + 2, get_s<S, 1002>('c'));
- while (!d6c.empty()) {
- d6c.pop_back();
- assert(is_double_ended_contiguous_container_asan_correct(d6c));
- }
- }
- {
- C d7(9 * N + 2);
-
- d7.insert(d7.begin() + 1, S());
- verify_inside(d7);
-
- d7.insert(d7.end() - 3, S());
- verify_inside(d7);
-
- d7.insert(d7.begin() + 2 * N, get_s<S, 1>('a'));
- verify_inside(d7);
-
- d7.insert(d7.end() - 2 * N, get_s<S, 1>('b'));
- verify_inside(d7);
-
- d7.insert(d7.begin() + 2 * N, 3 * N, get_s<S, 1>('c'));
- verify_inside(d7);
-
- // It may not be short for big element types, but it will be checked correctly:
- d7.insert(d7.end() - 2 * N, 3 * N, get_s<S, 2>('d'));
- verify_inside(d7);
-
- d7.erase(d7.begin() + 2);
- verify_inside(d7);
-
- d7.erase(d7.end() - 2);
- verify_inside(d7);
- }
-}
-
-template <class S>
-void test_container() {
- test_string<std::deque<S, std::allocator<S>>, S>();
- test_string<std::deque<S, min_allocator<S>>, S>();
- test_string<std::deque<S, safe_allocator<S>>, S>();
-}
-
-int main(int, char**) {
- // Those tests support only types based on std::basic_string.
- test_container<std::string>();
- test_container<std::wstring>();
-#if TEST_STD_VER >= 11
- test_container<std::u16string>();
- test_container<std::u32string>();
-#endif
-#if TEST_STD_VER >= 20
- test_container<std::u8string>();
-#endif
-
- return 0;
-}
diff --git a/libcxx/test/libcxx/containers/strings/basic.string/asan_short.pass.cpp b/libcxx/test/libcxx/containers/strings/basic.string/asan_short.pass.cpp
deleted file mode 100644
index 53c70bed189b5c..00000000000000
--- a/libcxx/test/libcxx/containers/strings/basic.string/asan_short.pass.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// REQUIRES: asan
-// UNSUPPORTED: c++03
-
-// <string>
-
-// Basic test if ASan annotations work for short strings.
-
-#include <string>
-#include <cassert>
-#include <cstdlib>
-
-#include "asan_testing.h"
-#include "min_allocator.h"
-#include "test_iterators.h"
-#include "test_macros.h"
-
-extern "C" void __sanitizer_set_death_callback(void (*callback)(void));
-
-void do_exit() { exit(0); }
-
-int main(int, char**) {
- {
- typedef cpp17_input_iterator<char*> MyInputIter;
- // Should not trigger ASan.
- std::basic_string<char, std::char_traits<char>, safe_allocator<char>> v;
- char i[] = {'a', 'b', 'c', 'd'};
-
- v.insert(v.begin(), MyInputIter(i), MyInputIter(i + 4));
- assert(v[0] == 'a');
- assert(is_string_asan_correct(v));
- }
-
- __sanitizer_set_death_callback(do_exit);
- {
- using T = char;
- using C = std::basic_string<T, std::char_traits<T>, safe_allocator<T>>;
- const T t[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
- C c(std::begin(t), std::end(t));
- assert(is_string_asan_correct(c));
- assert(__sanitizer_verify_contiguous_container(c.data(), c.data() + c.size() + 1, c.data() + c.capacity() + 1) !=
- 0);
- volatile T foo = c[c.size() + 1]; // should trigger ASAN. Use volatile to prevent being optimized away.
- assert(false); // if we got here, ASAN didn't trigger
- ((void)foo);
- }
-
- return 0;
-}
diff --git a/libcxx/test/libcxx/containers/strings/basic.string/asan_vector_integration.pass.cpp b/libcxx/test/libcxx/containers/strings/basic.string/asan_vector_integration.pass.cpp
deleted file mode 100644
index 5b1900fb00d5bb..00000000000000
--- a/libcxx/test/libcxx/containers/strings/basic.string/asan_vector_integration.pass.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// REQUIRES: asan
-// UNSUPPORTED: c++03
-
-#include <cassert>
-#include <string>
-#include <vector>
-#include <array>
-#include "test_macros.h"
-#include "asan_testing.h"
-#include "min_allocator.h"
-
-// This tests exists to check if strings work well with vector, as those
-// may be partialy annotated, we cannot simply call
-// is_contiguous_container_asan_correct, as it assumes that
-// object memory inside is not annotated, so we check everything in a more careful way.
-
-template <typename D>
-void verify_inside(D const& d) {
- for (size_t i = 0; i < d.size(); ++i) {
- assert(is_string_asan_correct(d[i]));
- }
-}
-
-template <typename S, size_t N>
-S get_s(char c) {
- S s;
- for (size_t i = 0; i < N; ++i)
- s.push_back(c);
-
- return s;
-}
-
-template <class C, class S>
-void test_string() {
- size_t const N = sizeof(S) < 256 ? (4096 / sizeof(S)) : 16;
-
- {
- C d1a(1), d1b(N), d1c(N + 1), d1d(32 * N);
- verify_inside(d1a);
- verify_inside(d1b);
- verify_inside(d1c);
- verify_inside(d1d);
- }
- {
- C d2;
- for (size_t i = 0; i < 16 * N; ++i) {
- d2.push_back(get_s<S, 1>(i % 10 + 'a'));
- verify_inside(d2);
- d2.push_back(get_s<S, 222>(i % 10 + 'b'));
- verify_inside(d2);
-
- d2.erase(d2.cbegin());
- verify_inside(d2);
- }
- }
- {
- C d3;
- for (size_t i = 0; i < 16 * N; ++i) {
- d3.push_back(get_s<S, 1>(i % 10 + 'a'));
- verify_inside(d3);
- d3.push_back(get_s<S, 222>(i % 10 + 'b'));
- verify_inside(d3);
-
- d3.pop_back();
- verify_inside(d3);
- }
- }
- {
- C d4;
- for (size_t i = 0; i < 16 * N; ++i) {
- // When there is no SSO, all elements inside should not be poisoned,
- // so we can verify vector poisoning.
- d4.push_back(get_s<S, 333>(i % 10 + 'a'));
- verify_inside(d4);
- assert(is_contiguous_container_asan_correct(d4));
- d4.push_back(get_s<S, 222>(i % 10 + 'b'));
- verify_inside(d4);
- assert(is_contiguous_container_asan_correct(d4));
- }
- }
- {
- C d5;
- for (size_t i = 0; i < 5 * N; ++i) {
- // In d4 we never had poisoned memory inside vector.
- // Here we start with SSO, so part of the inside of the container,
- // will be poisoned.
- d5.push_back(S());
- verify_inside(d5);
- }
- for (size_t i = 0; i < d5.size(); ++i) {
- // We change the size to have long string.
- // Memory owne by vector should not be poisoned by string.
- d5[i].resize(1000);
- verify_inside(d5);
- }
-
- assert(is_contiguous_container_asan_correct(d5));
-
- d5.erase(d5.begin() + 2);
- verify_inside(d5);
-
- d5.erase(d5.end() - 2);
- verify_inside(d5);
-
- assert(is_contiguous_container_asan_correct(d5));
- }
- {
- C d6a;
- assert(is_contiguous_container_asan_correct(d6a));
-
- C d6b(N + 2, get_s<S, 1000>('a'));
- d6b.push_back(get_s<S, 1001>('b'));
- while (!d6b.empty()) {
- d6b.pop_back();
- assert(is_contiguous_container_asan_correct(d6b));
- }
-
- C d6c(N + 2, get_s<S, 1002>('c'));
- while (!d6c.empty()) {
- d6c.pop_back();
- assert(is_contiguous_container_asan_correct(d6c));
- }
- }
- {
- C d7(9 * N + 2);
-
- d7.insert(d7.begin() + 1, S());
- verify_inside(d7);
-
- d7.insert(d7.end() - 3, S());
- verify_inside(d7);
-
- d7.insert(d7.begin() + 2 * N, get_s<S, 1>('a'));
- verify_inside(d7);
-
- d7.insert(d7.end() - 2 * N, get_s<S, 1>('b'));
- verify_inside(d7);
-
- d7.insert(d7.begin() + 2 * N, 3 * N, get_s<S, 1>('c'));
- verify_inside(d7);
-
- // It may not be short for big element types, but it will be checked correctly:
- d7.insert(d7.end() - 2 * N, 3 * N, get_s<S, 2>('d'));
- verify_inside(d7);
-
- d7.erase(d7.begin() + 2);
- verify_inside(d7);
-
- d7.erase(d7.end() - 2);
- verify_inside(d7);
- }
-}
-
-template <class S>
-void test_container() {
- test_string<std::vector<S, std::allocator<S>>, S>();
- test_string<std::vector<S, min_allocator<S>>, S>();
- test_string<std::vector<S, safe_allocator<S>>, S>();
-}
-
-int main(int, char**) {
- // Those tests support only types based on std::basic_string.
- test_container<std::string>();
- test_container<std::wstring>();
-#if TEST_STD_VER >= 11
- test_container<std::u16string>();
- test_container<std::u32string>();
-#endif
-#if TEST_STD_VER >= 20
- test_container<std::u8string>();
-#endif
-
- return 0;
-}
diff --git a/libcxx/test/support/asan_testing.h b/libcxx/test/support/asan_testing.h
index 3785c1f9c20dea..6bfc8280a4ead3 100644
--- a/libcxx/test/support/asan_testing.h
+++ b/libcxx/test/support/asan_testing.h
@@ -56,16 +56,35 @@ TEST_CONSTEXPR bool is_double_ended_contiguous_container_asan_correct(const std:
#endif
#if TEST_HAS_FEATURE(address_sanitizer)
+template <typename S>
+bool is_string_short(S const& s) {
+ // We do not have access to __is_long(), but we can check if strings
+ // buffer is inside strings memory. If strings memory contains its content,
+ // SSO is in use. To check it, we can just confirm that the beginning is in
+ // the string object memory block.
+ // &s - beginning of objects memory
+ // &s[0] - beginning of the buffer
+ // (&s+1) - end of objects memory
+ return (void*)std::addressof(s) <= (void*)std::addressof(s[0]) &&
+ (void*)std::addressof(s[0]) < (void*)(std::addressof(s) + 1);
+}
+
template <typename ChrT, typename TraitsT, typename Alloc>
TEST_CONSTEXPR bool is_string_asan_correct(const std::basic_string<ChrT, TraitsT, Alloc>& c) {
if (TEST_IS_CONSTANT_EVALUATED)
return true;
- if (std::__asan_annotate_container_with_allocator<Alloc>::value)
- return __sanitizer_verify_contiguous_container(c.data(), c.data() + c.size() + 1, c.data() + c.capacity() + 1) != 0;
- else
- return __sanitizer_verify_contiguous_container(
- c.data(), c.data() + c.capacity() + 1, c.data() + c.capacity() + 1) != 0;
+ if (!is_string_short(c) || _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED) {
+ if (std::__asan_annotate_container_with_allocator<Alloc>::value)
+ return __sanitizer_verify_contiguous_container(c.data(), c.data() + c.size() + 1, c.data() + c.capacity() + 1) !=
+ 0;
+ else
+ return __sanitizer_verify_contiguous_container(
+ c.data(), c.data() + c.capacity() + 1, c.data() + c.capacity() + 1) != 0;
+ } else {
+ return __sanitizer_verify_contiguous_container(std::addressof(c), std::addressof(c) + 1, std::addressof(c) + 1) !=
+ 0;
+ }
}
#else
# include <string>
|
I'm going to spend next few hours on debugging it. Unfortunately, I can't run buildbots locally to debug it and test potential solutions (tried to run them as described here: https://github.com/google/sanitizers/wiki/SanitizerBotReproduceBuild but eventually I run into some issues, around end of compilation or during testing). I'm not a fan of reverting this patch without a small example showing a problem with it, but because However, @vitalybuka could you confirm before reverting short string annotations that reverting lambda optimization fix (#77394) does not fix that issue? Unfortunately, I can't run buildbots locally or reproduce it in any other way. I will aslo appreciate help with running buildbots locally and creating a small example showing the issue. I will ask more on Discord as that should be easier. |
That's not how it work. If we don't understand the problem, we revert, and investigate later.
It should be possible to reproduce on GCE, using that instructions. It recreates VM using those scripts daily. Another alternative: if you give me a pull request, from the branch in users/ of the main repo, I can schedule execution on bot directly.
Sure, I will help you with debugging on bot. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not how it work. If we don't understand the problem, we revert, and investigate later.
Ok.
Yes. At least https://lab.llvm.org/buildbot/#/builders/239/builds/5361 seems like it may be related to it, but that's a guess based on previous issues with it (and fact that this very line is mentioned in the ASan error).
Thank you! I appreciate it! |
@vitalybuka Thx for checking it! Good to know that it's something else. |
This commit unpoisons memory before using memory as different types/before memset. Buildobts were failing and therefore short string annotations were turned off. Here: llvm#78627 This commit unpoisons memory before debug "scribble across the rest of the storage", as well as before reinterpret cast of an union.
Originally merged here: #75882 Reverted here: #78627 Reverted due to failing buildbots. The problem was not caused by the annotations code, but by code in the `UniqueFunctionBase` class and in the `JSON.h` file. That code caused the program to write to memory that was already being used by string objects, which resulted in an ASan error. Fixes are implemented in: - #79065 - #79066 Problematic code from `UniqueFunctionBase` for example: ```cpp #ifndef NDEBUG // In debug builds, we also scribble across the rest of the storage. memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize); #endif ``` --- Original description: This commit turns on ASan annotations in `std::basic_string` for short stings (SSO case). Originally suggested here: https://reviews.llvm.org/D147680 String annotations added here: #72677 Requires to pass CI without fails: - #75845 - #75858 Annotating `std::basic_string` with default allocator is implemented in #72677 but annotations for short strings (SSO - Short String Optimization) are turned off there. This commit turns them on. This also removes `_LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED`, because we do not plan to support turning on and off short string annotations. Support in ASan API exists since dd1b7b7. You can turn off annotations for a specific allocator based on changes from 2fa1bec. This PR is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector` and `std::deque` collections. These enhancements empower ASan to effectively detect instances where the instrumented program attempts to access memory within a collection's internal allocation that remains unused. This includes cases where access occurs before or after the stored elements in `std::deque`, or between the `std::basic_string`'s size (including the null terminator) and capacity bounds. The introduction of these annotations was spurred by a real-world software bug discovered by Trail of Bits, involving an out-of-bounds memory access during the comparison of two strings using the `std::equals` function. This function was taking iterators (`iter1_begin`, `iter1_end`, `iter2_begin`) to perform the comparison, using a custom comparison function. When the `iter1` object exceeded the length of `iter2`, an out-of-bounds read could occur on the `iter2` object. Container sanitization, upon enabling these annotations, would effectively identify and flag this potential vulnerability. If you have any questions, please email: [email protected] [email protected]
Originally merged here: #75882 Reverted here: #78627 Reverted due to failing buildbots. The problem was not caused by the annotations code, but by code in the `UniqueFunctionBase` class and in the `JSON.h` file. That code caused the program to write to memory that was already being used by string objects, which resulted in an ASan error. Fixes are implemented in: - #79065 - #79066 Problematic code from `UniqueFunctionBase` for example: ```cpp #ifndef NDEBUG // In debug builds, we also scribble across the rest of the storage. memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize); #endif ```
This is 3rd attempt to upstream short string annotations, it's the same as the previous one, but other PRs fixed issues withing LLVM: - llvm#79489 - llvm#79522 Additionaly annotations were updated (but it shouldn't have any impact on anything): - llvm#79292 Now, as far as I know, all buildbots should work without problems. Both previous reverts were not related to issues with string annotations, but with issues in LLVM/clang. Read PRs above and below for details. --- Previous description: Originally merged here: llvm#75882 Reverted here: llvm#78627 Reverted due to failing buildbots. The problem was not caused by the annotations code, but by code in the `UniqueFunctionBase` class and in the `JSON.h` file. That code caused the program to write to memory that was already being used by string objects, which resulted in an ASan error. Fixes are implemented in: - llvm#79065 - llvm#79066 Problematic code from `UniqueFunctionBase` for example: ```cpp // In debug builds, we also scribble across the rest of the storage. memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize); ``` --- Original description: This commit turns on ASan annotations in `std::basic_string` for short stings (SSO case). Originally suggested here: https://reviews.llvm.org/D147680 String annotations added here: llvm#72677 Requires to pass CI without fails: - llvm#75845 - llvm#75858 Annotating `std::basic_string` with default allocator is implemented in llvm#72677 but annotations for short strings (SSO - Short String Optimization) are turned off there. This commit turns them on. This also removes `_LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED`, because we do not plan to support turning on and off short string annotations. Support in ASan API exists since llvm@dd1b7b7. You can turn off annotations for a specific allocator based on changes from llvm@2fa1bec. This PR is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector` and `std::deque` collections. These enhancements empower ASan to effectively detect instances where the instrumented program attempts to access memory within a collection's internal allocation that remains unused. This includes cases where access occurs before or after the stored elements in `std::deque`, or between the `std::basic_string`'s size (including the null terminator) and capacity bounds. The introduction of these annotations was spurred by a real-world software bug discovered by Trail of Bits, involving an out-of-bounds memory access during the comparison of two strings using the `std::equals` function. This function was taking iterators (`iter1_begin`, `iter1_end`, `iter2_begin`) to perform the comparison, using a custom comparison function. When the `iter1` object exceeded the length of `iter2`, an out-of-bounds read could occur on the `iter2` object. Container sanitization, upon enabling these annotations, would effectively identify and flag this potential vulnerability. If you have any questions, please email: [email protected] [email protected]
Originally merged here: #75882 Reverted here: #78627 Reverted due to failing buildbots. The problem was not caused by the annotations code, but by code in the `UniqueFunctionBase` class and in the `JSON.h` file. That code caused the program to write to memory that was already being used by string objects, which resulted in an ASan error. Fixes are implemented in: - #79065 - #79066 Problematic code from `UniqueFunctionBase` for example: ```cpp // In debug builds, we also scribble across the rest of the storage. memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize); ```
Originally merged here: llvm/llvm-project#75882 Reverted here: llvm/llvm-project#78627 Reverted due to failing buildbots. The problem was not caused by the annotations code, but by code in the `UniqueFunctionBase` class and in the `JSON.h` file. That code caused the program to write to memory that was already being used by string objects, which resulted in an ASan error. Fixes are implemented in: - llvm/llvm-project#79065 - llvm/llvm-project#79066 Problematic code from `UniqueFunctionBase` for example: ```cpp #ifndef NDEBUG // In debug builds, we also scribble across the rest of the storage. memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize); #endif ``` --- Original description: This commit turns on ASan annotations in `std::basic_string` for short stings (SSO case). Originally suggested here: https://reviews.llvm.org/D147680 String annotations added here: llvm/llvm-project#72677 Requires to pass CI without fails: - llvm/llvm-project#75845 - llvm/llvm-project#75858 Annotating `std::basic_string` with default allocator is implemented in llvm/llvm-project#72677 but annotations for short strings (SSO - Short String Optimization) are turned off there. This commit turns them on. This also removes `_LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED`, because we do not plan to support turning on and off short string annotations. Support in ASan API exists since llvm/llvm-project@dd1b7b7. You can turn off annotations for a specific allocator based on changes from llvm/llvm-project@2fa1bec. This PR is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector` and `std::deque` collections. These enhancements empower ASan to effectively detect instances where the instrumented program attempts to access memory within a collection's internal allocation that remains unused. This includes cases where access occurs before or after the stored elements in `std::deque`, or between the `std::basic_string`'s size (including the null terminator) and capacity bounds. The introduction of these annotations was spurred by a real-world software bug discovered by Trail of Bits, involving an out-of-bounds memory access during the comparison of two strings using the `std::equals` function. This function was taking iterators (`iter1_begin`, `iter1_end`, `iter2_begin`) to perform the comparison, using a custom comparison function. When the `iter1` object exceeded the length of `iter2`, an out-of-bounds read could occur on the `iter2` object. Container sanitization, upon enabling these annotations, would effectively identify and flag this potential vulnerability. If you have any questions, please email: [email protected] [email protected] NOKEYCHECK=True GitOrigin-RevId: cb528ec5e6331ce207c7b835d7ab963bd5e13af7
This is 3rd attempt to upstream short string annotations, it's the same as the previous one, but other PRs fixed issues withing LLVM: - llvm#79489 - llvm#79522 Additionaly annotations were updated (but it shouldn't have any impact on anything): - llvm#79292 Now, as far as I know, all buildbots should work without problems. Both previous reverts were not related to issues with string annotations, but with issues in LLVM/clang. Read PRs above and below for details. --- Previous description: Originally merged here: llvm#75882 Reverted here: llvm#78627 Reverted due to failing buildbots. The problem was not caused by the annotations code, but by code in the `UniqueFunctionBase` class and in the `JSON.h` file. That code caused the program to write to memory that was already being used by string objects, which resulted in an ASan error. Fixes are implemented in: - llvm#79065 - llvm#79066 Problematic code from `UniqueFunctionBase` for example: ```cpp // In debug builds, we also scribble across the rest of the storage. memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize); ``` --- Original description: This commit turns on ASan annotations in `std::basic_string` for short stings (SSO case). Originally suggested here: https://reviews.llvm.org/D147680 String annotations added here: llvm#72677 Requires to pass CI without fails: - llvm#75845 - llvm#75858 Annotating `std::basic_string` with default allocator is implemented in llvm#72677 but annotations for short strings (SSO - Short String Optimization) are turned off there. This commit turns them on. This also removes `_LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED`, because we do not plan to support turning on and off short string annotations. Support in ASan API exists since llvm@dd1b7b7. You can turn off annotations for a specific allocator based on changes from llvm@2fa1bec. This PR is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector` and `std::deque` collections. These enhancements empower ASan to effectively detect instances where the instrumented program attempts to access memory within a collection's internal allocation that remains unused. This includes cases where access occurs before or after the stored elements in `std::deque`, or between the `std::basic_string`'s size (including the null terminator) and capacity bounds. The introduction of these annotations was spurred by a real-world software bug discovered by Trail of Bits, involving an out-of-bounds memory access during the comparison of two strings using the `std::equals` function. This function was taking iterators (`iter1_begin`, `iter1_end`, `iter2_begin`) to perform the comparison, using a custom comparison function. When the `iter1` object exceeded the length of `iter2`, an out-of-bounds read could occur on the `iter2` object. Container sanitization, upon enabling these annotations, would effectively identify and flag this potential vulnerability. If you have any questions, please email: [email protected] [email protected]
This is 3rd attempt to upstream short string annotations, it's the same as the previous one, but other PRs fixed issues withing LLVM: - llvm#79489 - llvm#79522 Additionaly annotations were updated (but it shouldn't have any impact on anything): - llvm#79292 Now, as far as I know, all buildbots should work without problems. Both previous reverts were not related to issues with string annotations, but with issues in LLVM/clang. Read PRs above and below for details. --- Previous description: Originally merged here: llvm#75882 Reverted here: llvm#78627 Reverted due to failing buildbots. The problem was not caused by the annotations code, but by code in the `UniqueFunctionBase` class and in the `JSON.h` file. That code caused the program to write to memory that was already being used by string objects, which resulted in an ASan error. Fixes are implemented in: - llvm#79065 - llvm#79066 Problematic code from `UniqueFunctionBase` for example: ```cpp // In debug builds, we also scribble across the rest of the storage. memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize); ``` --- Original description: This commit turns on ASan annotations in `std::basic_string` for short stings (SSO case). Originally suggested here: https://reviews.llvm.org/D147680 String annotations added here: llvm#72677 Requires to pass CI without fails: - llvm#75845 - llvm#75858 Annotating `std::basic_string` with default allocator is implemented in llvm#72677 but annotations for short strings (SSO - Short String Optimization) are turned off there. This commit turns them on. This also removes `_LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED`, because we do not plan to support turning on and off short string annotations. Support in ASan API exists since llvm@dd1b7b7. You can turn off annotations for a specific allocator based on changes from llvm@2fa1bec. This PR is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector` and `std::deque` collections. These enhancements empower ASan to effectively detect instances where the instrumented program attempts to access memory within a collection's internal allocation that remains unused. This includes cases where access occurs before or after the stored elements in `std::deque`, or between the `std::basic_string`'s size (including the null terminator) and capacity bounds. The introduction of these annotations was spurred by a real-world software bug discovered by Trail of Bits, involving an out-of-bounds memory access during the comparison of two strings using the `std::equals` function. This function was taking iterators (`iter1_begin`, `iter1_end`, `iter2_begin`) to perform the comparison, using a custom comparison function. When the `iter1` object exceeded the length of `iter2`, an out-of-bounds read could occur on the `iter2` object. Container sanitization, upon enabling these annotations, would effectively identify and flag this potential vulnerability. If you have any questions, please email: [email protected] [email protected]
This is 3rd attempt to upstream short string annotations, it's the same as the previous one, but other PRs fixed issues withing LLVM: - llvm#79489 - llvm#79522 Additionaly annotations were updated (but it shouldn't have any impact on anything): - llvm#79292 Now, as far as I know, all buildbots should work without problems. Both previous reverts were not related to issues with string annotations, but with issues in LLVM/clang. Read PRs above and below for details. --- Previous description: Originally merged here: llvm#75882 Reverted here: llvm#78627 Reverted due to failing buildbots. The problem was not caused by the annotations code, but by code in the `UniqueFunctionBase` class and in the `JSON.h` file. That code caused the program to write to memory that was already being used by string objects, which resulted in an ASan error. Fixes are implemented in: - llvm#79065 - llvm#79066 Problematic code from `UniqueFunctionBase` for example: ```cpp // In debug builds, we also scribble across the rest of the storage. memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize); ``` --- Original description: This commit turns on ASan annotations in `std::basic_string` for short stings (SSO case). Originally suggested here: https://reviews.llvm.org/D147680 String annotations added here: llvm#72677 Requires to pass CI without fails: - llvm#75845 - llvm#75858 Annotating `std::basic_string` with default allocator is implemented in llvm#72677 but annotations for short strings (SSO - Short String Optimization) are turned off there. This commit turns them on. This also removes `_LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED`, because we do not plan to support turning on and off short string annotations. Support in ASan API exists since llvm@dd1b7b7. You can turn off annotations for a specific allocator based on changes from llvm@2fa1bec. This PR is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector` and `std::deque` collections. These enhancements empower ASan to effectively detect instances where the instrumented program attempts to access memory within a collection's internal allocation that remains unused. This includes cases where access occurs before or after the stored elements in `std::deque`, or between the `std::basic_string`'s size (including the null terminator) and capacity bounds. The introduction of these annotations was spurred by a real-world software bug discovered by Trail of Bits, involving an out-of-bounds memory access during the comparison of two strings using the `std::equals` function. This function was taking iterators (`iter1_begin`, `iter1_end`, `iter2_begin`) to perform the comparison, using a custom comparison function. When the `iter1` object exceeded the length of `iter2`, an out-of-bounds read could occur on the `iter2` object. Container sanitization, upon enabling these annotations, would effectively identify and flag this potential vulnerability. If you have any questions, please email: [email protected] [email protected]
This pull request is the third iteration aiming to integrate short string annotations. This commit includes: - Enabling basic_string annotations for short strings. - Setting a value of `__trivially_relocatable` in `std::basic_string` to `false_type` when compiling with ASan (nothing changes when compiling without ASan). Short string annotations make `std::basic_string` to not be trivially relocatable, because memory has to be unpoisoned. - Adding a `_LIBCPP_STRING_INTERNAL_MEMORY_ACCESS` modifier to two functions. - Creating a macro `_LIBCPP_ASAN_VOLATILE_WRAPPER` to prevent problematic stack optimizations (the macro modifies code behavior only when compiling with ASan). Previously we had issues with compiler optimization, which we understand thanks to @vitalybuka. This commit also addresses smaller changes in short string, since previous upstream attempts. Problematic optimization was loading two values in code similar to: ``` __is_long() ? __get_long_size() : __get_short_size(); ``` We aim to resolve it with the volatile wrapper. This commit is built on top of two previous attempts which descriptions are below. Additionally, in the meantime, annotations were updated (but it shouldn't have any impact on anything): - #79292 --- Previous PR: #79049 Reverted: a16f81f Previous description: Originally merged here: #75882 Reverted here: #78627 Reverted due to failing buildbots. The problem was not caused by the annotations code, but by code in the `UniqueFunctionBase` class and in the `JSON.h` file. That code caused the program to write to memory that was already being used by string objects, which resulted in an ASan error. Fixes are implemented in: - #79065 - #79066 Problematic code from `UniqueFunctionBase` for example: ```cpp // In debug builds, we also scribble across the rest of the storage. memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize); ``` --- Original description: This commit turns on ASan annotations in `std::basic_string` for short stings (SSO case). Originally suggested here: https://reviews.llvm.org/D147680 String annotations added here: #72677 Requires to pass CI without fails: - #75845 - #75858 Annotating `std::basic_string` with default allocator is implemented in #72677 but annotations for short strings (SSO - Short String Optimization) are turned off there. This commit turns them on. This also removes `_LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED`, because we do not plan to support turning on and off short string annotations. Support in ASan API exists since dd1b7b7. You can turn off annotations for a specific allocator based on changes from 2fa1bec. This PR is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector` and `std::deque` collections. These enhancements empower ASan to effectively detect instances where the instrumented program attempts to access memory within a collection's internal allocation that remains unused. This includes cases where access occurs before or after the stored elements in `std::deque`, or between the `std::basic_string`'s size (including the null terminator) and capacity bounds. The introduction of these annotations was spurred by a real-world software bug discovered by Trail of Bits, involving an out-of-bounds memory access during the comparison of two strings using the `std::equals` function. This function was taking iterators (`iter1_begin`, `iter1_end`, `iter2_begin`) to perform the comparison, using a custom comparison function. When the `iter1` object exceeded the length of `iter2`, an out-of-bounds read could occur on the `iter2` object. Container sanitization, upon enabling these annotations, would effectively identify and flag this potential vulnerability. If you have any questions, please email: - [email protected] - [email protected]
Reverts #75882
To recover build bots :
https://lab.llvm.org/buildbot/#/builders/239/builds/5361
https://lab.llvm.org/buildbot/#/builders/168/builds/18126