public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] Update PMR allocators for CHERI
@ 2022-10-26 11:06 Matthew Malcomson
  0 siblings, 0 replies; only message in thread
From: Matthew Malcomson @ 2022-10-26 11:06 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:70924d59c8f02388cbd22a3b6389126ca89e2fac

commit 70924d59c8f02388cbd22a3b6389126ca89e2fac
Author: Matthew Malcomson <matthew.malcomson@arm.com>
Date:   Wed Oct 26 12:04:38 2022 +0100

    Update PMR allocators for CHERI
    
    The allocation methods of the C++17 allocators based of the
    memory_resource interface are different to each other.  However it
    happens that the two main allocation methods naturally provide the
    ability to return precisely bounded pointers from allocation requests.
    
    The two allocator approaches built on top of memory_resource in
    libstdc++ are that for the monotonic_resource and that for the
    {un,}synchronized_pool_resource.
    
    ---
    The monotonic_resource is a very simple allocator.  It never reclaims
    memory that has been freed by the user.  This allocator maintains a
    large buffer (which it gets from `new`).  When an allocation is
    requested this allocator moves the "current" pointer along in this
    buffer an amount according to the allocation required.  The space left
    behind is the space given to the user.
    
    It is clear that returning a tightly bounded capability from such an
    allocation would cause no problems.
    
    ---
    The {un,}synchronized_pool_resource classes are more complicated.  These
    both maintain a set of pools from which to allocate, and each pool is
    implemented by a vector of `chunk` structures.  These `chunk` structures
    allocate blocks by determining which bits in a bitset are free.  An
    allocation consists of finding a free bit, returning a pointer generated
    from the base pointer to a chunk plus an offset according to which bit
    was chosen.  A deallocation consists of finding which bit in which chunk
    a pointer corresponded to and clearing that bit.
    
    Since the allocation is always generated from an internal base pointer
    and the deallocation only needs the address of a capability, providing a
    bounded pointer naturally fits with this mechanism of tracking
    allocations.  There is nothing to do beyond ensuring that the returned
    pointer is bounded according to the size of allocation.
    
    ---
    In contrast to the ext/pool_allocator and ext/mt_allocator, these
    allocators do allow allocations larger than the threshold at which we
    need to pay attention to padding and alignment concerns for CHERI
    precise bounds.
    
    To handle that we can use the two builtins introduced for this reason:
      - __builtin_cheri_round_representable_length
      - __builtin_cheri_representable_alignment_mask
    
    Across the allocator code there are a few places which look like they
    might need accounting for alignment but do not.  Here we justify the
    lack of extra code in each place.
    
    In __pool_resource::_Pool::replenish, we replenish the slab backing
    allocations.  This slab is obtained from some underlying allocator
    (by default the `new_delete_resource`, but could be anything provided by
    the user).  The alignment we request for this slab needs to be enough
    for the chunks that we give out (it is relied upon in the allocation
    routines of {un,}synchronized_pool_resource).  We can not rely on the
    underlying allocator providing us with an aligned pointer, since even if
    it is adjusted for CHERI precise bounds it is valid for the returned
    pointer to be unaligned with padding and bounds extending to smaller
    addresses than the pointer that is returned.  That means that the
    alignment we request must be as large as we require.
    
    It happens that the existing algorithm already ensures that the
    alignment requested is std::bit_ceil(__block_size) where __block_size is
    the size that this chunk will be handling.  Given the properties of
    CHERI bounds compression, this alignment is always enough to provide
    precise bounds on the given block size.
    
    {un,}synchronized_pool_resource chooses the block_size from which to
    satisfy allocations based on the maximum of the length and alignment
    requested.  This only relates to the block from which we satisfy
    requests, and does not affect the bytes we actually want to provide to
    the user.  Hence as long as we have adjusted our request for CHERI
    precise bounds before this adjustment there is no problem.
    
    ---
    There is a static assert in memory_resource.cc on the size of a `struct
    chunk`.  This is there to ensure that the padding at the end of a
    `struct bitset` is used in the chunk structure that inherits from it.
    The increased size and alignment requirements of a pointer on a CHERI
    architecture means that there is more padding in a `struct chunk`, and
    hence the static_assert fails with the existing expression.  Here we
    adjust the assertion expression and include a comment as to where the
    padding has come from.
    
    ---
    We had to update the testcase unsynchronized_pool_resource/allocate.cc
    to account for the fact that the size and alignment requested by the
    user may be modified by the time the allocation request is passed down
    to an underlying allocator.  We hence have to adjust the check according
    to CHERI bounds compression adjustments.

Diff:
---
 libstdc++-v3/include/std/memory_resource           | 34 +++++++++++++-
 libstdc++-v3/src/c++17/memory_resource.cc          | 52 +++++++++++++++++++---
 .../check_awkward_pool_size.cc                     | 44 ++++++++++++++++++
 .../check_read_out_of_bounds.cc                    | 40 +++++++++++++++++
 .../check_read_out_of_bounds_2.cc                  | 45 +++++++++++++++++++
 .../unsynchronized_pool_resource/allocate.cc       | 23 +++++++++-
 .../check_awkward_pool_size.cc                     | 41 +++++++++++++++++
 .../check_read_out_of_bounds.cc                    | 38 ++++++++++++++++
 .../check_read_out_of_bounds_2.cc                  | 43 ++++++++++++++++++
 9 files changed, 351 insertions(+), 9 deletions(-)

diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource
index 2b8735b8c39..56700bc3e23 100644
--- a/libstdc++-v3/include/std/memory_resource
+++ b/libstdc++-v3/include/std/memory_resource
@@ -129,6 +129,37 @@ namespace pmr
   { return !(__a == __b); }
 #endif
 
+  inline void
+  __maybe_cheri_round_allocation(size_t* __bytesp, size_t* __alignmentp)
+  noexcept
+    {
+#ifdef __CHERI_PURE_CAPABILITY__
+      size_t __bytes = *__bytesp;
+      size_t __alignment = *__alignmentp;
+      __bytes = __builtin_cheri_round_representable_length(__bytes);
+      // Check for overflow.  If overflow occured there's nothing we can do
+      // so we return without adjustment.
+      if (__bytes < *__bytesp)
+	return;
+      const size_t __alignment_mask
+	= __builtin_cheri_representable_alignment_mask(__bytes);
+      const size_t tmp = ((size_t)1) << __builtin_ctzl(__alignment_mask);
+      __alignment = std::max(tmp, __alignment);
+
+      *__bytesp = __bytes;
+      *__alignmentp = __alignment;
+#endif
+    }
+
+  inline void*
+  __maybe_cheri_bounded(void* __ret, size_t __length)
+    {
+#ifdef __CHERI_PURE_CAPABILITY__
+      __ret = __builtin_cheri_bounds_set_exact(__ret, __length);
+#endif
+      return __ret;
+    }
+
   // C++17 23.12.3 Class template polymorphic_allocator
   template<typename _Tp>
     class polymorphic_allocator
@@ -639,6 +670,7 @@ namespace pmr
       if (__bytes == 0)
 	__bytes = 1; // Ensures we don't return the same pointer twice.
 
+      __maybe_cheri_round_allocation(&__bytes, &__alignment);
       void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail);
       if (!__p)
 	{
@@ -647,7 +679,7 @@ namespace pmr
 	}
       _M_current_buf = (char*)_M_current_buf + __bytes;
       _M_avail -= __bytes;
-      return __p;
+      return __maybe_cheri_bounded(__p, __bytes);
     }
 
     void
diff --git a/libstdc++-v3/src/c++17/memory_resource.cc b/libstdc++-v3/src/c++17/memory_resource.cc
index facc3244538..ac397f21997 100644
--- a/libstdc++-v3/src/c++17/memory_resource.cc
+++ b/libstdc++-v3/src/c++17/memory_resource.cc
@@ -544,10 +544,22 @@ namespace pmr
   // For 32-bit and 20-bit pointers it's four pointers (16 bytes).
   // For 16-bit pointers it's five pointers (10 bytes).
   // TODO pad 64-bit to 4*sizeof(void*) to avoid splitting across cache lines?
-#ifndef __CHERI_PURE_CAPABILITY__
-  // MORELLO TODO: FIXME.  This code will need adapting for capabilities.
+#if __SIZEOF_POINTER__ <= 8
   static_assert(sizeof(chunk)
       == sizeof(bitset::size_type) + sizeof(uint32_t) + 2 * sizeof(void*));
+#elif __SIZEOF_POINTER__ == 16
+  // CHERI pointers on 64 bit targets are 128 bits (i.e. 16 bytes) in size.
+  // Hence there is extra padding required to align _M_p, even though we do
+  // manage to use some padding from bitset in the chunk definition.
+  // Similar question about padding for cache lines as is made above could
+  // apply here.
+  static_assert(sizeof(chunk)
+      == sizeof(bitset::size_type) + sizeof(uint32_t) + 2 * sizeof(void*) + 8);
+#else
+  // Do not make assertions for other sizes, any architectures with new pointer
+  // sizes may want to revisit this and decide for themselves if the current
+  // situation is acceptable to them.
+#error "New pointer size -- suggest investigating padding in PMR chunk struct."
 #endif
 
   // An oversized allocation that doesn't fit in a pool.
@@ -689,6 +701,7 @@ namespace pmr
       const size_t __words = (__blocks + __bits - 1) / __bits;
       const size_t __block_size = block_size();
       size_t __bytes = __blocks * __block_size + __words * sizeof(word);
+      // N.b. this alignment is also enough for CHERI precise bounds.
       size_t __alignment = std::__bit_ceil(__block_size);
       void* __p = __r->allocate(__bytes, __alignment);
       __try
@@ -912,6 +925,12 @@ namespace pmr
 	// Setting _M_opts to the largest pool allows users to query it:
 	opts.largest_required_pool_block = std::end(pool_sizes)[-1];
       }
+
+#ifdef __CHERI_PURE_CAPABILITY__
+    opts.largest_required_pool_block
+	    = __builtin_cheri_round_representable_length
+		    (opts.largest_required_pool_block);
+#endif
     return opts;
   }
 
@@ -1204,6 +1223,13 @@ namespace pmr
   synchronized_pool_resource::
   do_allocate(size_t bytes, size_t alignment)
   {
+    // N.b. this rounding up for a representable size is not needed when we
+    // request the size from `_M_impl`.  That __pool_resource would
+    // automatically handle adding associated bounds and rounding up since it
+    // would be passed to some "upstream" memory resource.
+    // That said, there is also no harm to adjusting the size we request here,
+    // and it makes the code slightly easier to read.
+    __maybe_cheri_round_allocation(&bytes, &alignment);
     const auto block_size = std::max(bytes, alignment);
     const pool_options opts = _M_impl._M_opts;
     if (block_size <= opts.largest_required_pool_block)
@@ -1217,7 +1243,7 @@ namespace pmr
 	      {
 		// Need exclusive lock to replenish so use try_allocate:
 		if (void* p = pools[index].try_allocate())
-		  return p;
+		  return __maybe_cheri_bounded(p, bytes);
 		// Need to take exclusive lock and replenish pool.
 	      }
 	    // Need to allocate or replenish thread-specific pools using
@@ -1230,7 +1256,9 @@ namespace pmr
 		exclusive_lock dummy(_M_mx);
 		_M_tpools = _M_alloc_shared_tpools(dummy);
 	      }
-	    return _M_tpools->pools[index].allocate(upstream_resource(), opts);
+	    void* ret
+	      = _M_tpools->pools[index].allocate(upstream_resource(), opts);
+	    return __maybe_cheri_bounded(ret, bytes);
 	  }
 
 	// N.B. Another thread could call release() now lock is not held.
@@ -1240,7 +1268,8 @@ namespace pmr
 	auto pools = _M_thread_specific_pools();
 	if (!pools)
 	  pools = _M_alloc_tpools(excl)->pools;
-	return pools[index].allocate(upstream_resource(), opts);
+	void* ret = pools[index].allocate(upstream_resource(), opts);
+	return __maybe_cheri_bounded(ret, bytes);
       }
     exclusive_lock l(_M_mx);
     return _M_impl.allocate(bytes, alignment); // unpooled allocation
@@ -1410,14 +1439,25 @@ namespace pmr
   void*
   unsynchronized_pool_resource::do_allocate(size_t bytes, size_t alignment)
   {
+    // N.b. this rounding up for a representable size is not needed when we
+    // request the size from `_M_impl`.  That __pool_resource would
+    // automatically handle adding associated bounds and rounding up since it
+    // would be passed to some "upstream" memory resource.
+    // That said, there is also no harm to adjusting the size we request here,
+    // and it makes the code slightly easier to read.
+    __maybe_cheri_round_allocation(&bytes, &alignment);
     const auto block_size = std::max(bytes, alignment);
+
     if (block_size <= _M_impl._M_opts.largest_required_pool_block)
       {
 	// Recreate pools if release() has been called:
 	if (__builtin_expect(_M_pools == nullptr, false))
 	  _M_pools = _M_impl._M_alloc_pools();
 	if (auto pool = _M_find_pool(block_size))
-	  return pool->allocate(upstream_resource(), _M_impl._M_opts);
+	  {
+	    void* ret = pool->allocate(upstream_resource(), _M_impl._M_opts);
+	    return __maybe_cheri_bounded(ret, bytes);
+	  }
       }
     return _M_impl.allocate(bytes, alignment);
   }
diff --git a/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/check_awkward_pool_size.cc b/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/check_awkward_pool_size.cc
new file mode 100644
index 00000000000..cacd9379ccc
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/check_awkward_pool_size.cc
@@ -0,0 +1,44 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run }
+// { dg-options "-std=gnu++17 -pthread" }
+// { dg-require-effective-target c++17 }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <memory_resource>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::pmr::synchronized_pool_resource r({0, 0x40130});
+  void * p1 = r.allocate(0x40008);
+  void * p2 = r.allocate(0x40008);
+#ifdef __CHERI_PURE_CAPABILITY__
+  VERIFY ( (size_t)p1 == __builtin_cheri_base_get (p1));
+  VERIFY ( (size_t)p2 == __builtin_cheri_base_get (p2));
+#endif
+}
+
+int
+main()
+{
+  test01();
+}
+
diff --git a/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/check_read_out_of_bounds.cc b/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/check_read_out_of_bounds.cc
new file mode 100644
index 00000000000..df99c38c084
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/check_read_out_of_bounds.cc
@@ -0,0 +1,40 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run }
+// { dg-options "-std=gnu++17 -pthread" }
+// { dg-require-effective-target c++17 }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+// { dg-shouldfail-purecap "out of bounds" }
+
+#include <memory_resource>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::pmr::synchronized_pool_resource r;
+  char *ret = (char *)r.allocate (8, 1);
+  ret[8] = 'x';  // BOOM for purecap.
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/check_read_out_of_bounds_2.cc b/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/check_read_out_of_bounds_2.cc
new file mode 100644
index 00000000000..c1b7de46d2a
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/check_read_out_of_bounds_2.cc
@@ -0,0 +1,45 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run }
+// { dg-options "-std=gnu++17 -pthread" }
+// { dg-require-effective-target c++17 }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+// { dg-shouldfail-purecap "out of bounds" }
+
+#include <memory_resource>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::pmr::synchronized_pool_resource r;
+  // Allocate twice so that the second allocation is from the same allocation
+  // as the first (and hence that with non-CHERI-bounded allocations we can
+  // access one byte before the second allocation).
+  char *ret = (char *)r.allocate (8, 1);
+  char *ret2 = (char *)r.allocate (8, 1);
+  ret[1] = 'x';
+  ret2[-1] = 'x';  // BOOM for purecap.
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/allocate.cc b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/allocate.cc
index 5bf20cf262c..0e8466bf6c3 100644
--- a/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/allocate.cc
+++ b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/allocate.cc
@@ -186,9 +186,28 @@ test06()
 	return std::pmr::new_delete_resource()->allocate(bytes, align);
 
       // This is a large, unpooled allocation. Check the arguments:
-      if (bytes < expected_size)
+      size_t size_expect = expected_size;
+      size_t alignment_expect = expected_alignment;
+#ifdef __CHERI_PURE_CAPABILITY__
+      // Since allocations need to be padded and bounded by the allocator for
+      // precise bounds on CHERI architectures, we account for that here.
+      {
+	size_t s = expected_size;
+	size_t size_tmp = __builtin_cheri_round_representable_length (s);
+	size_t mask = __builtin_cheri_representable_alignment_mask (s);
+	size_t alignment_tmp = 1UL << __builtin_ctzl(mask);
+	// Check for overflow.  Nothing is done in the allocators if there is
+	// overflow in the rounding of representable length.
+	if (size_tmp >= expected_size)
+	  {
+	    alignment_expect = std::max (alignment_tmp, expected_alignment);
+	    size_expect = std::max (size_tmp, expected_size);
+	  }
+      }
+#endif
+      if (bytes < size_expect)
 	throw bad_size();
-      else if (align != expected_alignment)
+      else if (align != alignment_expect)
 	throw bad_alignment();
       // Else just throw, don't really try to allocate:
       throw std::bad_alloc();
diff --git a/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/check_awkward_pool_size.cc b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/check_awkward_pool_size.cc
new file mode 100644
index 00000000000..7e784d8f93e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/check_awkward_pool_size.cc
@@ -0,0 +1,41 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+#include <memory_resource>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::pmr::unsynchronized_pool_resource r({0, 0x40130});
+  void * p1 = r.allocate(0x40008);
+  void * p2 = r.allocate(0x40008);
+#ifdef __CHERI_PURE_CAPABILITY__
+  VERIFY ( (size_t)p1 == __builtin_cheri_base_get (p1));
+  VERIFY ( (size_t)p2 == __builtin_cheri_base_get (p2));
+#endif
+}
+
+int
+main()
+{
+  test01();
+}
+
diff --git a/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/check_read_out_of_bounds.cc b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/check_read_out_of_bounds.cc
new file mode 100644
index 00000000000..6a9e5e4f6df
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/check_read_out_of_bounds.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+// { dg-shouldfail-purecap "out of bounds" }
+
+#include <memory_resource>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::pmr::unsynchronized_pool_resource r;
+  char *ret = (char *)r.allocate (8, 1);
+  ret[8] = 'x';  // BOOM for purecap.
+}
+
+int
+main()
+{
+  test01();
+}
+
diff --git a/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/check_read_out_of_bounds_2.cc b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/check_read_out_of_bounds_2.cc
new file mode 100644
index 00000000000..83b09c287fb
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/check_read_out_of_bounds_2.cc
@@ -0,0 +1,43 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+// { dg-shouldfail-purecap "out of bounds" }
+
+#include <memory_resource>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::pmr::unsynchronized_pool_resource r;
+  // Allocate twice so that the second allocation is from the same allocation
+  // as the first (and hence that with non-CHERI-bounded allocations we can
+  // access one byte before the second allocation).
+  char *ret = (char *)r.allocate (8, 1);
+  char *ret2 = (char *)r.allocate (8, 1);
+  ret[1] = 'x';
+  ret2[-1] = 'x';  // BOOM for purecap.
+}
+
+int
+main()
+{
+  test01();
+}
+

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-10-26 11:06 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-26 11:06 [gcc(refs/vendors/ARM/heads/morello)] Update PMR allocators for CHERI Matthew Malcomson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).