brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.5 KiB · f7390ef Raw
208 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// REQUIRES: has-unix-headers10// UNSUPPORTED: c++03, c++11, c++14, c++1711// UNSUPPORTED: libcpp-hardening-mode=none12// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing13 14// <memory>15//16// unique_ptr<T[]>17//18// T& operator[](std::size_t);19 20// This test ensures that we catch an out-of-bounds access in std::unique_ptr<T[]>::operator[]21// when unique_ptr has the appropriate ABI configuration.22 23#include <memory>24#include <cstddef>25#include <string>26 27#include "check_assertion.h"28#include "type_algorithms.h"29#include "test_macros.h"30 31struct MyDeleter {32  MyDeleter() = default;33 34  // required to exercise converting move-constructor35  template <class T>36  MyDeleter(std::default_delete<T> const&) {}37 38  // required to exercise converting move-assignment39  template <class T>40  MyDeleter& operator=(std::default_delete<T> const&) {41    return *this;42  }43 44  template <class T>45  void operator()(T* ptr) const {46    delete[] ptr;47  }48};49 50template <class WithCookie, class NoCookie>51void test() {52  LIBCPP_STATIC_ASSERT(std::__has_array_cookie<WithCookie>::value);53  LIBCPP_STATIC_ASSERT(!std::__has_array_cookie<NoCookie>::value);54 55  // For types with an array cookie, we can always detect OOB accesses. Note that reliance on an array56  // cookie is limited to the default deleter, since a unique_ptr with a custom deleter may not have57  // been allocated with `new T[n]`.58  {59    {60      std::unique_ptr<WithCookie[]> ptr(new WithCookie[5]);61      assert(&ptr[1] == ptr.get() + 1); // ensure no assertion62      TEST_LIBCPP_ASSERT_FAILURE(ptr[6], "unique_ptr<T[]>::operator[](index): index out of range");63    }64    {65      std::unique_ptr<WithCookie[]> ptr = std::make_unique<WithCookie[]>(5);66      assert(&ptr[1] == ptr.get() + 1); // ensure no assertion67      TEST_LIBCPP_ASSERT_FAILURE(ptr[6], "unique_ptr<T[]>::operator[](index): index out of range");68    }69#if TEST_STD_VER >= 2070    {71      std::unique_ptr<WithCookie[]> ptr = std::make_unique_for_overwrite<WithCookie[]>(5);72      assert(&ptr[1] == ptr.get() + 1); // ensure no assertion73      TEST_LIBCPP_ASSERT_FAILURE(ptr[6] = WithCookie(), "unique_ptr<T[]>::operator[](index): index out of range");74    }75#endif76  }77 78  // For types that don't have an array cookie, things are a bit more complicated. We can detect OOB accesses79  // only when the unique_ptr is created via an API where the size is passed down to the library so that we80  // can store it inside the unique_ptr. That requires the appropriate ABI configuration to be enabled.81  //82  // Note that APIs that allow the size to be passed down to the library only support the default deleter83  // as of writing this test.84#if defined(_LIBCPP_ABI_BOUNDED_UNIQUE_PTR)85  {86    {87      std::unique_ptr<NoCookie[]> ptr = std::make_unique<NoCookie[]>(5);88      assert(&ptr[1] == ptr.get() + 1); // ensure no assertion89      TEST_LIBCPP_ASSERT_FAILURE(ptr[6], "unique_ptr<T[]>::operator[](index): index out of range");90    }91#  if TEST_STD_VER >= 2092    {93      std::unique_ptr<NoCookie[]> ptr = std::make_unique_for_overwrite<NoCookie[]>(5);94      assert(&ptr[1] == ptr.get() + 1); // ensure no assertion95      TEST_LIBCPP_ASSERT_FAILURE(ptr[6] = NoCookie(), "unique_ptr<T[]>::operator[](index): index out of range");96    }97#  endif98  }99#endif100 101  // Make sure that we carry the bounds information properly through conversions, assignments, etc.102  // These tests are only relevant when the ABI setting is enabled (with a stateful bounds-checker).103#if defined(_LIBCPP_ABI_BOUNDED_UNIQUE_PTR)104  types::for_each(types::type_list<NoCookie, WithCookie>(), []<class T> {105    // Bounds carried through move construction106    {107      std::unique_ptr<T[]> ptr = std::make_unique<T[]>(5);108      std::unique_ptr<T[]> other(std::move(ptr));109      assert(&other[1] == other.get() + 1); // ensure no assertion110      TEST_LIBCPP_ASSERT_FAILURE(other[6], "unique_ptr<T[]>::operator[](index): index out of range");111    }112 113    // Bounds carried through move assignment114    {115      std::unique_ptr<T[]> ptr = std::make_unique<T[]>(5);116      std::unique_ptr<T[]> other;117      other = std::move(ptr);118      assert(&other[1] == other.get() + 1); // ensure no assertion119      TEST_LIBCPP_ASSERT_FAILURE(other[6], "unique_ptr<T[]>::operator[](index): index out of range");120    }121 122    // Bounds carried through converting move-constructor123    {124      std::unique_ptr<T[]> ptr = std::make_unique<T[]>(5);125      std::unique_ptr<T[], MyDeleter> other(std::move(ptr));126      assert(&other[1] == other.get() + 1); // ensure no assertion127      TEST_LIBCPP_ASSERT_FAILURE(other[6], "unique_ptr<T[]>::operator[](index): index out of range");128    }129 130    // Bounds carried through converting move-assignment131    {132      std::unique_ptr<T[]> ptr = std::make_unique<T[]>(5);133      std::unique_ptr<T[], MyDeleter> other;134      other = std::move(ptr);135      assert(&other[1] == other.get() + 1); // ensure no assertion136      TEST_LIBCPP_ASSERT_FAILURE(other[6], "unique_ptr<T[]>::operator[](index): index out of range");137    }138  });139#endif140}141 142template <std::size_t Size>143struct NoCookie {144  char padding[Size];145};146 147template <std::size_t Size>148struct WithCookie {149  WithCookie() = default;150  WithCookie(WithCookie const&) {}151  WithCookie& operator=(WithCookie const&) { return *this; }152  ~WithCookie() {}153  char padding[Size];154};155 156template <std::size_t Size>157struct alignas(128) OveralignedNoCookie {158  char padding[Size];159};160 161template <std::size_t Size>162struct alignas(128) OveralignedWithCookie {163  OveralignedWithCookie() = default;164  OveralignedWithCookie(OveralignedWithCookie const&) {}165  OveralignedWithCookie& operator=(OveralignedWithCookie const&) { return *this; }166  ~OveralignedWithCookie() {}167  char padding[Size];168};169 170// These types have a different ABI alignment (alignof) and preferred alignment (__alignof) on some platforms.171// Make sure things work with these types because array cookies can be sensitive to preferred alignment on some172// platforms.173struct WithCookiePreferredAlignment {174  WithCookiePreferredAlignment() = default;175  WithCookiePreferredAlignment(WithCookiePreferredAlignment const&) {}176  WithCookiePreferredAlignment& operator=(WithCookiePreferredAlignment const&) { return *this; }177  ~WithCookiePreferredAlignment() {}178  long double data;179};180struct NoCookiePreferredAlignment {181  long double data;182};183 184int main(int, char**) {185  test<WithCookie<1>, NoCookie<1>>();186  test<WithCookie<2>, NoCookie<2>>();187  test<WithCookie<3>, NoCookie<3>>();188  test<WithCookie<4>, NoCookie<4>>();189  test<WithCookie<8>, NoCookie<8>>();190  test<WithCookie<16>, NoCookie<16>>();191  test<WithCookie<32>, NoCookie<32>>();192  test<WithCookie<256>, NoCookie<256>>();193 194  test<OveralignedWithCookie<1>, OveralignedNoCookie<1>>();195  test<OveralignedWithCookie<2>, OveralignedNoCookie<2>>();196  test<OveralignedWithCookie<3>, OveralignedNoCookie<3>>();197  test<OveralignedWithCookie<4>, OveralignedNoCookie<4>>();198  test<OveralignedWithCookie<8>, OveralignedNoCookie<8>>();199  test<OveralignedWithCookie<16>, OveralignedNoCookie<16>>();200  test<OveralignedWithCookie<32>, OveralignedNoCookie<32>>();201  test<OveralignedWithCookie<256>, OveralignedNoCookie<256>>();202 203  test<std::string, int>();204  test<WithCookiePreferredAlignment, NoCookiePreferredAlignment>();205 206  return 0;207}208