Skip to content
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

[libc++] Add an ABI setting to harden unique_ptr<T[]>::operator[] #91798

Merged
merged 1 commit into from
Sep 27, 2024

Conversation

ldionne
Copy link
Member

@ldionne ldionne commented May 10, 2024

This allows catching OOB accesses inside unique_ptr<T[]> when the size
of the allocation is known. The size of the allocation can be known when
the unique_ptr has been created with make_unique & friends or when the
type necessitates an array cookie before the allocation.

@ldionne ldionne requested a review from a team as a code owner May 10, 2024 19:41
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label May 10, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented May 10, 2024

@llvm/pr-subscribers-libcxx

Author: Louis Dionne (ldionne)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/91798.diff

5 Files Affected:

  • (modified) libcxx/cmake/caches/Generic-hardening-mode-fast-with-abi-breaks.cmake (+1-1)
  • (modified) libcxx/include/__config (+3)
  • (modified) libcxx/include/__memory/unique_ptr.h (+34-2)
  • (added) libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/assert.subscript.pass.cpp (+42)
  • (modified) libcxx/utils/libcxx/test/features.py (+1)
diff --git a/libcxx/cmake/caches/Generic-hardening-mode-fast-with-abi-breaks.cmake b/libcxx/cmake/caches/Generic-hardening-mode-fast-with-abi-breaks.cmake
index 4860b590dcde9..e9c90cc6bedf8 100644
--- a/libcxx/cmake/caches/Generic-hardening-mode-fast-with-abi-breaks.cmake
+++ b/libcxx/cmake/caches/Generic-hardening-mode-fast-with-abi-breaks.cmake
@@ -1,2 +1,2 @@
 set(LIBCXX_HARDENING_MODE "fast" CACHE STRING "")
-set(LIBCXX_ABI_DEFINES "_LIBCPP_ABI_BOUNDED_ITERATORS" CACHE STRING "")
+set(LIBCXX_ABI_DEFINES "_LIBCPP_ABI_BOUNDED_ITERATORS;_LIBCPP_ABI_BOUNDED_UNIQUE_PTR" CACHE STRING "")
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 104a244cc82cc..26b3a1e4c1115 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -206,6 +206,9 @@
 // - `array`.
 // #define _LIBCPP_ABI_BOUNDED_ITERATORS
 
+// Tracks the bounds of the array owned by std::unique_ptr<T[]>, allowing it to trap when accessed out-of-bounds.
+// #define _LIBCPP_ABI_BOUNDED_UNIQUE_PTR
+
 // } ABI
 
 // HARDENING {
diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index 46d9405e31596..2ad28e25a7af7 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -39,6 +39,7 @@
 #include <__type_traits/type_identity.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>
+#include <__utility/private_constructor_tag.h>
 #include <cstddef>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -301,6 +302,21 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
 
 private:
   __compressed_pair<pointer, deleter_type> __ptr_;
+#ifdef _LIBCPP_ABI_BOUNDED_UNIQUE_PTR
+  // Under the "bounded unique_ptr" ABI, we store the size of the allocation when it is known.
+  // The size of the allocation can be known when unique_ptr is created via make_unique or a
+  // similar API, however it can't be known when constructed with e.g.
+  //
+  //    unique_ptr<T[]> ptr(new T[3]);
+  //
+  // In that case, we don't know the size of the allocation from within the unique_ptr.
+  // Semantically, we'd need to store `optional<size_t>`. However, since that is really
+  // heavy weight, we instead store a size_t and use 0 as a magic value meaning that we
+  // don't know the size. This means that we can't catch OOB accesses inside a unique_ptr
+  // with a 0-sized allocation, however since this is a degenerate case, it doesn't matter
+  // in practice.
+  size_t __size_ = 0;
+#endif
 
   template <class _From>
   struct _CheckArrayPointerConversion : is_same<_From, pointer> {};
@@ -397,6 +413,18 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) _NOEXCEPT
       : __ptr_(__u.release(), std::forward<deleter_type>(__u.get_deleter())) {}
 
+  // Constructor used by make_unique & friends to pass the size that was allocated
+  template <class _Ptr>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr(
+      __private_constructor_tag, _Ptr __ptr, size_t __size) _NOEXCEPT
+      : __ptr_(__ptr, __value_init_tag())
+#ifdef _LIBCPP_ABI_BOUNDED_UNIQUE_PTR
+      ,
+        __size_(__size)
+#endif
+  {
+  }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT {
     reset(__u.release());
     __ptr_.second() = std::forward<deleter_type>(__u.get_deleter());
@@ -434,6 +462,10 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator[](size_t __i) const {
+#ifdef _LIBCPP_ABI_BOUNDED_UNIQUE_PTR
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+        __size_ == 0 || __i < __size_, "unique_ptr<T[]>::operator[](index): index out of range");
+#endif
     return __ptr_.first()[__i];
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get() const _NOEXCEPT { return __ptr_.first(); }
@@ -624,7 +656,7 @@ template <class _Tp>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __unique_if<_Tp>::__unique_array_unknown_bound
 make_unique(size_t __n) {
   typedef __remove_extent_t<_Tp> _Up;
-  return unique_ptr<_Tp>(new _Up[__n]());
+  return unique_ptr<_Tp>(__private_constructor_tag(), new _Up[__n](), __n);
 }
 
 template <class _Tp, class... _Args>
@@ -643,7 +675,7 @@ make_unique_for_overwrite() {
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 typename __unique_if<_Tp>::__unique_array_unknown_bound
 make_unique_for_overwrite(size_t __n) {
-  return unique_ptr<_Tp>(new __remove_extent_t<_Tp>[__n]);
+  return unique_ptr<_Tp>(__private_constructor_tag(), new __remove_extent_t<_Tp>[__n], __n);
 }
 
 template <class _Tp, class... _Args>
diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/assert.subscript.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/assert.subscript.pass.cpp
new file mode 100644
index 0000000000000..dd722f0c838ef
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/assert.subscript.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: has-unix-headers
+// UNSUPPORTED: c++03, c++11
+// UNSUPPORTED: libcpp-hardening-mode=none
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+// REQUIRES: libcpp-has-abi-bounded-unique_ptr
+
+// <memory>
+//
+// unique_ptr<T[]>
+//
+// T& operator[](std::size_t);
+
+// This test ensures that we catch an out-of-bounds access in std::unique_ptr<T[]>::operator[]
+// when unique_ptr has the appropriate ABI configuration.
+
+#include <memory>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+  {
+    std::unique_ptr<int[]> ptr = std::make_unique<int[]>(5);
+    TEST_LIBCPP_ASSERT_FAILURE(ptr[6] = 42, "unique_ptr<T[]>::operator[](index): index out of range");
+  }
+
+#if TEST_STD_VER >= 20
+  {
+    std::unique_ptr<int[]> ptr = std::make_unique_for_overwrite<int[]>(5);
+    TEST_LIBCPP_ASSERT_FAILURE(ptr[6] = 42, "unique_ptr<T[]>::operator[](index): index out of range");
+  }
+#endif
+
+  return 0;
+}
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index c81b56b1af547..f154840430ec5 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -312,6 +312,7 @@ def _getAndroidDeviceApi(cfg):
     "_LIBCPP_NO_VCRUNTIME": "libcpp-no-vcruntime",
     "_LIBCPP_ABI_VERSION": "libcpp-abi-version",
     "_LIBCPP_ABI_BOUNDED_ITERATORS": "libcpp-has-abi-bounded-iterators",
+    "_LIBCPP_ABI_BOUNDED_UNIQUE_PTR": "libcpp-has-abi-bounded-unique_ptr",
     "_LIBCPP_HAS_NO_FILESYSTEM": "no-filesystem",
     "_LIBCPP_HAS_NO_RANDOM_DEVICE": "no-random-device",
     "_LIBCPP_HAS_NO_LOCALIZATION": "no-localization",

@ldionne
Copy link
Member Author

ldionne commented May 10, 2024

Note that this patch is kind of a WIP. Another approach could be to query the compiler or the system allocator for the size of the allocation. I actually think the compiler knows the size of the allocation cause it encodes it at the front of the allocation when calling operator new[], but I have to refresh my memory on this.

Copy link

github-actions bot commented May 10, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@efriedma-quic
Copy link
Collaborator

I actually think the compiler knows the size of the allocation cause it encodes it at the front of the allocation

Only when the element type has a non-trivial destructor.

@EricWF
Copy link
Member

EricWF commented May 10, 2024

A couple of things I would like us to investigate:

  1. Can we stash the size before the the array we allocate?
  2. What effect does this have on unique_ptr being passed in registers?

@jkorous-apple
Copy link
Contributor

jkorous-apple commented May 14, 2024

I actually think the compiler knows the size of the allocation cause it encodes it at the front of the allocation

Only when the element type has a non-trivial destructor.

That sounds like for such types we could use it for runtime check in operator[] without changing the layout. Is that right?
Do you see any catch?

EDIT: How crazy would it be to allow this for all types?

@efriedma-quic
Copy link
Collaborator

https://itanium-cxx-abi.github.io/cxx-abi/abi.html#array-cookies describes array cookies. If the cookie is present, I can't think of any reason it would be a problem for libc++ to read it.

If the cookie isn't present, though, we can't access it, and forcing the compiler to generate a cookie where it normally wouldn't generate one is ABI break.

@ldionne ldionne force-pushed the review/harden-unique_ptr-array branch from 4841e1a to 253485d Compare August 23, 2024 19:23
@ldionne
Copy link
Member Author

ldionne commented Aug 23, 2024

I updated the patch with a WIP attempt to use the array cookie when one is present. There are still things to fix and comments to address (e.g. maybe using SIZE_MAX is better to eliminate a branch), but I wanted to get this draft out there for comments. I think it's a pretty clever improvement to unique_ptr.

@ldionne
Copy link
Member Author

ldionne commented Aug 26, 2024

@vitalybuka I just stumbled upon -fno-sanitize-address-poison-custom-array-cookie and learned that ASAN sometimes poisons array cookies when a custom operator new is in use. I'm not certain I understand why poisoning the array cookie is legal even when we have a custom operator new[], but it seems like poisoning array cookies would interact badly with this patch. Do you have thoughts?

@ldionne ldionne force-pushed the review/harden-unique_ptr-array branch from 253485d to 4a453cf Compare August 26, 2024 21:23
// TODO: Use a builtin instead
// TODO: We should factor in the choice of the usual deallocation function in this determination.
template <class _Tp>
struct __has_array_cookie : _Not<is_trivially_destructible<_Tp> > {};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@efriedma-quic What do you think about this? It is a bit more conservative than we could be, but I don't really want to start trying to implement the resolution of operator delete[] in the library. It looks like a compiler builtin should be fairly easy to provide for both getting the array cookie and telling us whether an array cookie is available.

I'm curious to know whether you think this is a reasonable first implementation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems reasonable for now.

@ldionne ldionne force-pushed the review/harden-unique_ptr-array branch from 4a453cf to 0f56d47 Compare August 28, 2024 18:04
@vitalybuka
Copy link
Collaborator

vitalybuka commented Aug 29, 2024

@vitalybuka I just stumbled upon -fno-sanitize-address-poison-custom-array-cookie and learned that ASAN sometimes poisons array cookies when a custom operator new is in use. I'm not certain I understand why poisoning the array cookie is legal even when we have a custom operator new[], but it seems like poisoning array cookies would interact badly with this patch. Do you have thoughts?

I see this feature for the first time :)

Looks like @filcab added the feature. Before that custom new was omitted, then
https://reviews.llvm.org/D41301 made it more aggressive
https://reviews.llvm.org/D52615 added a flag to protect the behavior change from the patch above

And the doc string was gone with https://reviews.llvm.org/D133349

I believe this is off by default "use at your own risk" feature.

I guess it should be easy to support this case by __attribute__((no_sanitize("address"))) on __get_array_cookie

@ldionne ldionne added the hardening Issues related to the hardening effort label Sep 11, 2024
@ldionne ldionne force-pushed the review/harden-unique_ptr-array branch from 3aae45d to ffd681f Compare September 17, 2024 18:20
@ldionne ldionne force-pushed the review/harden-unique_ptr-array branch from ffd681f to c37a05e Compare September 25, 2024 18:51
This patch adds an ABI configuration that allows bounds-checking in
unique_ptr<T[]>::operator[] when it has been constructed with bounds
information in the API.

The patch also adds support for bounds-checking when an array cookie
is known to exist, which allows validating bounds without even changing
the ABI.

Drive-by changes:
- Improve the tests for `operator[]`
- Improve the tests for `.get()`
- Add a test for incomplete types support
@ldionne ldionne force-pushed the review/harden-unique_ptr-array branch from b23d82d to 76fc808 Compare September 26, 2024 17:23
@ldionne ldionne merged commit 45a09d1 into llvm:main Sep 27, 2024
65 checks passed
@ldionne ldionne deleted the review/harden-unique_ptr-array branch September 27, 2024 12:49
@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 27, 2024

LLVM Buildbot has detected a new failure on builder sanitizer-x86_64-linux-android running on sanitizer-buildbot-android while building libcxx at step 2 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/186/builds/2730

Here is the relevant piece of the build log for the reference
Step 2 (annotate) failure: 'python ../sanitizer_buildbot/sanitizers/zorg/buildbot/builders/sanitizers/buildbot_selector.py' (failure)
...
PASS: SanitizerCommon-asan-aarch64-Android :: Posix/posix_memalign-alignment.cpp (218 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/Linux/odr-vtable.cpp (219 of 1709)
PASS: HWAddressSanitizer-aarch64 :: TestCases/mem-intrinsics.c (220 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/atol_strict.c (221 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/Linux/clone_test.cpp (222 of 1709)
PASS: HWAddressSanitizer-aarch64 :: TestCases/use-after-free.c (223 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/Posix/halt_on_error-torture.cpp (224 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/global-overflow.cpp (225 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/atoll_strict.c (226 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/double-free.cpp (227 of 1709)
FAIL: HWAddressSanitizer-aarch64 :: TestCases/hwasan_symbolize_stack_overflow.cpp (228 of 1709)
******************** TEST 'HWAddressSanitizer-aarch64 :: TestCases/hwasan_symbolize_stack_overflow.cpp' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: rm -rf /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp; mkdir /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp
+ rm -rf /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp
+ mkdir /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp
RUN: at line 2: /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/sanitizer_common/android_commands/android_compile.py  /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/bin/clang   --target=aarch64-linux-android24 --sysroot=/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot --gcc-toolchain=/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64  -B/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64 -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta  -fuse-ld=lld  -gline-tables-only -fsanitize=hwaddress -fuse-ld=lld -mllvm -hwasan-globals -mllvm -hwasan-use-short-granules -mllvm -hwasan-instrument-landing-pads=0 -mllvm -hwasan-instrument-personality-functions -Wl,--build-id -g /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp -o /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow
+ /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/sanitizer_common/android_commands/android_compile.py /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/bin/clang --target=aarch64-linux-android24 --sysroot=/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot --gcc-toolchain=/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64 -B/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64 -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta -fuse-ld=lld -gline-tables-only -fsanitize=hwaddress -fuse-ld=lld -mllvm -hwasan-globals -mllvm -hwasan-use-short-granules -mllvm -hwasan-instrument-landing-pads=0 -mllvm -hwasan-instrument-personality-functions -Wl,--build-id -g /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp -o /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow
RUN: at line 3: env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not  /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow 16 2>&1 | hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index | FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,AFTER0
+ env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow 16
+ hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index
+ FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,AFTER0
/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/./bin/hwasan_symbolize:319: SyntaxWarning: invalid escape sequence '\['
  m = re.match(r'.*?(0x[0-9a-f]+):' + '([ ]*[\[ ][0-9a-f][0-9a-f]\]?)' * 16, line)
Could not find symbols for apex/com.android.runtime/lib64/bionic/libc.so
RUN: at line 4: env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not  /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow 17 2>&1 | hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index | FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,AFTER1
+ env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow 17
+ hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index
+ FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,AFTER1
/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/./bin/hwasan_symbolize:319: SyntaxWarning: invalid escape sequence '\['
  m = re.match(r'.*?(0x[0-9a-f]+):' + '([ ]*[\[ ][0-9a-f][0-9a-f]\]?)' * 16, line)
Could not find symbols for apex/com.android.runtime/lib64/bionic/libc.so
RUN: at line 5: env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not  /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow -1 2>&1 | hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index | FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,BEFORE1
+ env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow -1
+ hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index
+ FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,BEFORE1
/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/./bin/hwasan_symbolize:319: SyntaxWarning: invalid escape sequence '\['
  m = re.match(r'.*?(0x[0-9a-f]+):' + '([ ]*[\[ ][0-9a-f][0-9a-f]\]?)' * 16, line)
Could not find symbols for apex/com.android.runtime/lib64/bionic/libc.so
RUN: at line 6: env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not  /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow -17 2>&1 | hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index | FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,BEFORE17
+ env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow -17
+ hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index
+ FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,BEFORE17
/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/./bin/hwasan_symbolize:319: SyntaxWarning: invalid escape sequence '\['
  m = re.match(r'.*?(0x[0-9a-f]+):' + '([ ]*[\[ ][0-9a-f][0-9a-f]\]?)' * 16, line)
Could not find symbols for apex/com.android.runtime/lib64/bionic/libc.so
Step 31 (run lit tests [aarch64/bluejay-userdebug/TQ3A.230805.001]) failure: run lit tests [aarch64/bluejay-userdebug/TQ3A.230805.001] (failure)
...
PASS: SanitizerCommon-asan-aarch64-Android :: Posix/posix_memalign-alignment.cpp (218 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/Linux/odr-vtable.cpp (219 of 1709)
PASS: HWAddressSanitizer-aarch64 :: TestCases/mem-intrinsics.c (220 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/atol_strict.c (221 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/Linux/clone_test.cpp (222 of 1709)
PASS: HWAddressSanitizer-aarch64 :: TestCases/use-after-free.c (223 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/Posix/halt_on_error-torture.cpp (224 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/global-overflow.cpp (225 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/atoll_strict.c (226 of 1709)
PASS: AddressSanitizer-aarch64-android :: TestCases/double-free.cpp (227 of 1709)
FAIL: HWAddressSanitizer-aarch64 :: TestCases/hwasan_symbolize_stack_overflow.cpp (228 of 1709)
******************** TEST 'HWAddressSanitizer-aarch64 :: TestCases/hwasan_symbolize_stack_overflow.cpp' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: rm -rf /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp; mkdir /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp
+ rm -rf /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp
+ mkdir /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp
RUN: at line 2: /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/sanitizer_common/android_commands/android_compile.py  /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/bin/clang   --target=aarch64-linux-android24 --sysroot=/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot --gcc-toolchain=/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64  -B/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64 -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta  -fuse-ld=lld  -gline-tables-only -fsanitize=hwaddress -fuse-ld=lld -mllvm -hwasan-globals -mllvm -hwasan-use-short-granules -mllvm -hwasan-instrument-landing-pads=0 -mllvm -hwasan-instrument-personality-functions -Wl,--build-id -g /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp -o /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow
+ /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/sanitizer_common/android_commands/android_compile.py /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/bin/clang --target=aarch64-linux-android24 --sysroot=/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot --gcc-toolchain=/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64 -B/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/android_ndk/toolchains/llvm/prebuilt/linux-x86_64 -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta -fuse-ld=lld -gline-tables-only -fsanitize=hwaddress -fuse-ld=lld -mllvm -hwasan-globals -mllvm -hwasan-use-short-granules -mllvm -hwasan-instrument-landing-pads=0 -mllvm -hwasan-instrument-personality-functions -Wl,--build-id -g /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp -o /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow
RUN: at line 3: env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not  /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow 16 2>&1 | hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index | FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,AFTER0
+ env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow 16
+ hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index
+ FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,AFTER0
/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/./bin/hwasan_symbolize:319: SyntaxWarning: invalid escape sequence '\['
  m = re.match(r'.*?(0x[0-9a-f]+):' + '([ ]*[\[ ][0-9a-f][0-9a-f]\]?)' * 16, line)
Could not find symbols for apex/com.android.runtime/lib64/bionic/libc.so
RUN: at line 4: env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not  /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow 17 2>&1 | hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index | FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,AFTER1
+ env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow 17
+ hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index
+ FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,AFTER1
/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/./bin/hwasan_symbolize:319: SyntaxWarning: invalid escape sequence '\['
  m = re.match(r'.*?(0x[0-9a-f]+):' + '([ ]*[\[ ][0-9a-f][0-9a-f]\]?)' * 16, line)
Could not find symbols for apex/com.android.runtime/lib64/bionic/libc.so
RUN: at line 5: env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not  /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow -1 2>&1 | hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index | FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,BEFORE1
+ env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow -1
+ hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index
+ FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,BEFORE1
/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/./bin/hwasan_symbolize:319: SyntaxWarning: invalid escape sequence '\['
  m = re.match(r'.*?(0x[0-9a-f]+):' + '([ ]*[\[ ][0-9a-f][0-9a-f]\]?)' * 16, line)
Could not find symbols for apex/com.android.runtime/lib64/bionic/libc.so
RUN: at line 6: env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not  /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow -17 2>&1 | hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index | FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,BEFORE17
+ env HWASAN_OPTIONS=disable_allocator_tagging=1:random_tags=0:fail_without_syscall_abi=0:abort_on_error=0:symbolize=0 not /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp/hwasan_overflow -17
+ hwasan_symbolize --symbols /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/compiler_rt_build_android_aarch64/test/hwasan/AARCH64/TestCases/Output/hwasan_symbolize_stack_overflow.cpp.tmp --index
+ FileCheck /var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm-project/compiler-rt/test/hwasan/TestCases/hwasan_symbolize_stack_overflow.cpp --check-prefixes=CHECK,BEFORE17
/var/lib/buildbot/sanitizer-buildbot6/sanitizer-x86_64-linux-android/build/llvm_build64/./bin/hwasan_symbolize:319: SyntaxWarning: invalid escape sequence '\['
  m = re.match(r'.*?(0x[0-9a-f]+):' + '([ ]*[\[ ][0-9a-f][0-9a-f]\]?)' * 16, line)
Could not find symbols for apex/com.android.runtime/lib64/bionic/libc.so

@ldionne
Copy link
Member Author

ldionne commented Sep 27, 2024

LLVM Buildbot has detected a new failure on builder sanitizer-x86_64-linux-android running on sanitizer-buildbot-android while building libcxx at step 2 "annotate".
[...]

I looked into it and I don't think this is caused by the patch, since the test doesn't use unique_ptr.

Sterling-Augustine pushed a commit to Sterling-Augustine/llvm-project that referenced this pull request Sep 27, 2024
…vm#91798)

This allows catching OOB accesses inside `unique_ptr<T[]>` when the size
of the allocation is known. The size of the allocation can be known when
the unique_ptr has been created with make_unique & friends or when the
type necessitates an array cookie before the allocation.
llvm-beanz added a commit to llvm-beanz/llvm-project that referenced this pull request Sep 28, 2024
ldionne added a commit that referenced this pull request Sep 30, 2024
…1798)

This allows catching OOB accesses inside `unique_ptr<T[]>` when the size
of the allocation is known. The size of the allocation can be known when
the unique_ptr has been created with make_unique & friends or when the
type necessitates an array cookie before the allocation.

This is a re-aplpication of 45a09d1 which had been reverted in
f11abac due to unrelated CI failures.
@nico
Copy link
Contributor

nico commented Sep 30, 2024

This makes the attached program crash (…in most runs, not 100% of the time):

unique.cc.zip

 % out/gn/bin/clang++ unique.cc -isysroot $(xcrun -show-sdk-path) -std=c++20 -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE     
% ./a.out
zsh: trace trap  ./a.out

lldb shows that this indeed this check:

    frame #0: 0x00000001000029e4 a.out`std::__1::unique_ptr<std::__1::vector<int, std::__1::allocator<int>> [], AlignedDeleter<std::__1::vector<int, std::__1::allocator<int>>>>::operator[][abi:se200000](unsigned long) const [inlined] __clang_trap_msg$libc++$/Users/thakis/src/llvm-project/out/gn/bin/../include/c++/v1/__memory/unique_ptr.h:566: assertion __checker_.__in_bounds(std::__to_address(__ptr_), __i) failed: unique_ptr<T[]>::operator[](index): index out of range

The program uses a unique_ptr with a custom deleter to refer to raw malloc-ed memory, "to allow having uninitialized entries inside it".

It has this typedef:

template <typename T>
using AlignedUniquePtr =
    std::unique_ptr<T, AlignedDeleter<typename std::remove_extent<T>::type>>;

It uses this typedef with an array type:

  // Underlying storage. It's raw malloc-ed rather than being a unique_ptr<T[]>
  // to allow having uninitialized entries inside it.
  AlignedUniquePtr<T[]> entries_;

It creates objects of this unique_ptr like so:

template <typename T>
AlignedUniquePtr<T> AlignedAllocTyped(size_t n_membs) {
  using TU = typename std::remove_extent<T>::type;
  return AlignedUniquePtr<T>(
      static_cast<TU*>(AlignedAlloc(alignof(TU), sizeof(TU) * n_membs)));
}

AlignedAlloc() is basically malloc – in particular, nothing calls new[], so it doesn't write an array cookie.

The custom deleter looks like so (AlignedFree() is just free()):

template <typename T>
struct AlignedDeleter {
  inline void operator()(T* ptr) const { AlignedFree(ptr); }
};

The class containing entries_ calls dtors as needed, and the deleter really only needs to free memory. delete [] is never called.

Is this a valid use of unique_ptr<T[]>? If so, should this hardening only be used for unique_ptrs that don't have a custom deleter?

@nico
Copy link
Contributor

nico commented Oct 1, 2024

Looking through 20.3.1.4 unique_ptr for array objects with a runtime length [unique.ptr.runtime], it says "— The default deleter will call delete[]." which implies that looking for the array cookie on itanium is ok with the default deleter, but other than that it doesn't say anything. So I think the code in the example is probably correct, and this diagnostic isn't – with a custom deleter, it can introduce an out-of-bounds read for valid code.

@ldionne
Copy link
Member Author

ldionne commented Oct 1, 2024

I think you're entirely correct. I'm working on a patch.

@ldionne
Copy link
Member Author

ldionne commented Oct 1, 2024

In fact, the memory held by the unique_ptr would not even have to be allocated. It could point to a stack variable and the deleter could be a no-op. In that sense, unique_ptr with a custom deleter is a bit closer to a scope_guard. I think I had that in mind when I made the first implementation a few months, but when I picked it back up recently I remember thinking "oh well it works for custom deleters as well" -- but that was a mistake.

VitaNuo pushed a commit to VitaNuo/llvm-project that referenced this pull request Oct 2, 2024
…vm#91798)

This allows catching OOB accesses inside `unique_ptr<T[]>` when the size
of the allocation is known. The size of the allocation can be known when
the unique_ptr has been created with make_unique & friends or when the
type necessitates an array cookie before the allocation.

This is a re-aplpication of 45a09d1 which had been reverted in
f11abac due to unrelated CI failures.
VitaNuo pushed a commit to VitaNuo/llvm-project that referenced this pull request Oct 2, 2024
…vm#91798)

This allows catching OOB accesses inside `unique_ptr<T[]>` when the size
of the allocation is known. The size of the allocation can be known when
the unique_ptr has been created with make_unique & friends or when the
type necessitates an array cookie before the allocation.

This is a re-aplpication of 45a09d1 which had been reverted in
f11abac due to unrelated CI failures.
xgupta pushed a commit to xgupta/llvm-project that referenced this pull request Oct 4, 2024
…vm#91798)

This allows catching OOB accesses inside `unique_ptr<T[]>` when the size
of the allocation is known. The size of the allocation can be known when
the unique_ptr has been created with make_unique & friends or when the
type necessitates an array cookie before the allocation.
xgupta pushed a commit to xgupta/llvm-project that referenced this pull request Oct 4, 2024
…vm#91798)

This allows catching OOB accesses inside `unique_ptr<T[]>` when the size
of the allocation is known. The size of the allocation can be known when
the unique_ptr has been created with make_unique & friends or when the
type necessitates an array cookie before the allocation.

This is a re-aplpication of 45a09d1 which had been reverted in
f11abac due to unrelated CI failures.
@alexfh
Copy link
Contributor

alexfh commented Oct 5, 2024

What about a case when a std::unique_ptr<T[]> with a default deleter temporarily points to a memory allocated with something but new T[]? If the code ensures the pointer is always reset before std::unique_ptr is destroyed, and the default deleter is never used. Something like in this example: https://gcc.godbolt.org/z/4fczP6e1q

If we skip the question why would one do that at all (I'm about to ask the author(s)), it seems like this is a valid use of the std::unique_ptr<> according to the C++20 standard. Or am I missing something?

It seems like the newly added bounds check accesses invalid memory trying to read the array cookie, which is not there. In the above compiler explorer link one can see how it results in a memory sanitizer error. Internally we observe a similar code triggering an "index out of range" assertion when accessing a valid index.

// meaning that we don't know the size.
struct __unique_ptr_array_bounds_stored {
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __unique_ptr_array_bounds_stored() : __size_(SIZE_MAX) {}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __unique_ptr_array_bounds_stored(size_t __size) : __size_(__size) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In file included from SSHSession.cc:35:
In file included from ./SSHSession.h:39:
In file included from ./a2netcompat.h:94:
In file included from /build/install/x86_64-w64-mingw32/include/c++/v1/string:648:
In file included from /build/install/x86_64-w64-mingw32/include/c++/v1/string_view:958:
In file included from /build/install/x86_64-w64-mingw32/include/c++/v1/algorithm:1851:
In file included from /build/install/x86_64-w64-mingw32/include/c++/v1/__algorithm/for_each.h:16:
In file included from /build/install/x86_64-w64-mingw32/include/c++/v1/__ranges/movable_box.h:21:
In file included from /build/install/x86_64-w64-mingw32/include/c++/v1/optional:1297:
In file included from /build/install/x86_64-w64-mingw32/include/c++/v1/memory:944:
In file included from /build/install/x86_64-w64-mingw32/include/c++/v1/__memory/inout_ptr.h:16:
In file included from /build/install/x86_64-w64-mingw32/include/c++/v1/__memory/shared_ptr.h:32:
/build/install/x86_64-w64-mingw32/include/c++/v1/__memory/unique_ptr.h:379:88: error: use of undeclared identifier 'SIZE_MAX'
  379 |   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __unique_ptr_array_bounds_stored() : __size_(SIZE_MAX) {}
      |                                                                                        ^
1 error generated.

This causes the above error when building aria2. If I replace it with __SIZE_MAX__ I won't get the error.

llvm-mingw nightly

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SIZE_MAX is supposed to be defined in <cstdint>, can you check why your platform doesn't provide it?

@ldionne
Copy link
Member Author

ldionne commented Oct 9, 2024

@var-const Thanks for the comments! See #111704.

@ldionne
Copy link
Member Author

ldionne commented Oct 9, 2024

What about a case when a std::unique_ptr<T[]> with a default deleter temporarily points to a memory allocated with something but new T[]? If the code ensures the pointer is always reset before std::unique_ptr is destroyed, and the default deleter is never used. Something like in this example: https://gcc.godbolt.org/z/4fczP6e1q

If we skip the question why would one do that at all (I'm about to ask the author(s)), it seems like this is a valid use of the std::unique_ptr<> according to the C++20 standard. Or am I missing something?

I'm not certain, but I think it's invalid. I think we're walking on an extremely thin line here, see below.

First, about whether this should be valid (I don't think you disagree, I just want to write it down): std::unique_ptr is meant to be used for memory management, and if you perform your own memory management and only use std::unique_ptr as a glorified raw pointer (like in the godbolt link), there's really no point to using std::unique_ptr at all. In fact, that std::unique_ptr is really weird since reset() can't be called on it, it can't be destroyed, etc. Otherwise, the deleter (std::default_delete in this case) would be called on the pointer, and that's invalid because of how that pointer was allocated. I think it would be really unfortunate for it to be considered valid by the Standard since the intent of std::unique_ptr is clear, and supporting such a contrived use case would prevent us from providing value to the 99% of use cases that are normal.

Now, about whether this is actually, technically, valid. unique.ptr#single.general-1 says this:

The default type for the template parameter D is default_delete. A client-supplied template argument D shall be a function object type ([function.objects]), lvalue reference to function, or lvalue reference to function object type for which, given a value d of type D and a value ptr of type unique_ptr<T, D>​::​pointer, the expression d(ptr) is valid and has the effect of disposing of the pointer as appropriate for that deleter.

I am tempted to say that the requirements on a custom deleter's validity also apply to the default deleter. Furthermore, that may be stretching it a bit, but I would say that this requirement is not satisfied in the case you showed above because the expression d(ptr) does not have the effect of disposing of the pointer as appropriate [for that deleter].

To be unambiguous, we should perhaps add something to the various std::unique_ptr constructors that says "the pointer used to initialized the unique_ptr must be such that calling the deleter on it disposes of the pointer in a valid way", but we'd have to be careful not to step on the toes of unique_ptr's ability to hold incomplete types.

Frankly, I'm not certain what to do with this. I feel like it would be really unfortunate to drop this hardening check on a slightly ambiguous technicality since it can deliver a ton of value in the real world. I think I'll email the reflector to see what the sentiment is like over there.

@alexfh
Copy link
Contributor

alexfh commented Oct 9, 2024

Thanks for the detailed analysis. I totally agree with the conclusions here. The value of this hardening is obvious, while the ability to (mis-)use unique_ptr this way is questionable on its own. Luckily (though no surprise ;) this was an isolated case and the code has already been fixed.

To be unambiguous, we should perhaps add something to the various std::unique_ptr constructors that says "the pointer used to initialized the unique_ptr must be such that calling the deleter on it disposes of the pointer in a valid way", but we'd have to be careful not to step on the toes of unique_ptr's ability to hold incomplete types.

Making this part of the standard unambiguous would definitely be welcome.

Frankly, I'm not certain what to do with this. I feel like it would be really unfortunate to drop this hardening check on a slightly ambiguous technicality since it can deliver a ton of value in the real world. I think I'll email the reflector to see what the sentiment is like over there.

I almost feel sorry for bringing this up ;) But hopefully, this will result in improving the standard rather than creating an obstacle for library hardenings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hardening Issues related to the hardening effort libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.