File: overwrite.cc

package info (click to toggle)
gcc-arm-none-eabi 15%3A12.2.rel1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 959,712 kB
  • sloc: cpp: 3,275,382; ansic: 2,061,766; ada: 840,956; f90: 208,513; makefile: 76,132; asm: 73,433; xml: 50,448; exp: 34,146; sh: 32,436; objc: 15,637; fortran: 14,012; python: 11,991; pascal: 6,787; awk: 4,779; perl: 3,054; yacc: 338; ml: 285; lex: 201; haskell: 122
file content (143 lines) | stat: -rw-r--r-- 4,176 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// { dg-options "-std=gnu++20 -fno-lifetime-dse -O0" }
// { dg-do run { target c++20 } }

// C++20 20.11.3.7 shared_ptr Creation [util.smartptr.shared.create]

#include <memory>

#ifndef __cpp_lib_smart_ptr_for_overwrite
# error "Feature-test macro for make_shared_for_overwrite missing in <memory>"
#elif __cpp_lib_smart_ptr_for_overwrite < 202002L
# error "Feature-test macro for make_shared_for_overwrite has wrong value in <memory>"
#endif

#include <cstring>
#include <testsuite_hooks.h>

int counter = 0;

template<typename T>
struct Alloc : std::allocator<T>
{
  Alloc() = default;

  template<typename U>
    Alloc(const Alloc<U>&) { }

  T* allocate(std::size_t n)
  {
    ++counter;
    void* p = std::allocator<T>::allocate(n);
    // need -fno-lifetime-dse to check for these values later.
    std::memset(p, 0xff, n * sizeof(T));
    return (T*)p;
  }

  void construct(auto*, auto&&...)
  {
    // The objects must be default-initialized, not using this function.
    VERIFY( ! "allocator_traits::construct" );
  }

  void destroy(auto*)
  {
    // The objects must be destroyed by ~T(), not using this function.
    VERIFY( ! "allocator_traits::destroy" );
  }
};

void
test01()
{
  Alloc<int> a;
  const int expected = 0xffffffff;

  std::shared_ptr<int> p1 = std::allocate_shared_for_overwrite<int>(a);
  VERIFY( counter == 1 );
  VERIFY( *p1 == expected );
  std::shared_ptr<int[44]> p2 = std::allocate_shared_for_overwrite<int[44]>(a);
  VERIFY( counter == 2 );
  VERIFY( p2[0] == expected );
  p2.reset();
  std::shared_ptr<int[]> p3 = std::allocate_shared_for_overwrite<int[]>(a, 88);
  VERIFY( counter == 3 );
  VERIFY( p3[0] == expected );
  VERIFY( p3[87] == expected );
  std::shared_ptr<int[3][4]> p4 = std::allocate_shared_for_overwrite<int[3][4]>(a);
  VERIFY( counter == 4 );
  VERIFY( p4[0][0] == expected );
  VERIFY( p4[2][3] == expected );
  std::shared_ptr<int[][5]> p5 = std::allocate_shared_for_overwrite<int[][5]>(a, 6);
  VERIFY( counter == 5 );
  VERIFY( p5[0][0] == expected );
  VERIFY( p5[5][4] == expected );

  struct BigBoi { int x[100]; };
  std::shared_ptr<BigBoi> p6 = std::allocate_shared_for_overwrite<BigBoi>(a);
  VERIFY( counter == 6 );
  VERIFY( p6->x[0] == expected );
  std::shared_ptr<BigBoi[22]> p7 = std::allocate_shared_for_overwrite<BigBoi[22]>(a);
  VERIFY( counter == 7 );
  VERIFY( p7[0].x[0] == expected );
  VERIFY( p7[21].x[99] == expected );
  std::shared_ptr<BigBoi[]> p8 = std::allocate_shared_for_overwrite<BigBoi[]>(a, 11);
  VERIFY( counter == 8 );
  VERIFY( p8[0].x[0] == expected );
  VERIFY( p8[10].x[10] == expected );
}

void
test02()
{
  // These aren't created by the custom allocator, so we can't check that the
  // memory was left uninitialized. Just dereference them.

  std::shared_ptr<int> p1 = std::make_shared_for_overwrite<int>();
  (void) *p1;
  std::shared_ptr<int[44]> p2 = std::make_shared_for_overwrite<int[44]>();
  (void) p2[0];
  std::shared_ptr<int[]> p3 = std::make_shared_for_overwrite<int[]>(88);
  (void) p3[0];
  (void) p3[87];
  std::shared_ptr<int[3][4]> p4 = std::make_shared_for_overwrite<int[3][4]>();
  (void) p4[0][0];
  (void) p4[2][3];
  std::shared_ptr<int[][5]> p5 = std::make_shared_for_overwrite<int[][5]>(6);
  (void) p5[0][0];
  (void) p5[5][4];

  struct BigBoi { int x[100]; };
  std::shared_ptr<BigBoi> p6 = std::make_shared_for_overwrite<BigBoi>();
  (void) p6->x[0];
  std::shared_ptr<BigBoi[22]> p7 = std::make_shared_for_overwrite<BigBoi[22]>();
  (void) p7[0].x[0];
  (void) p7[21].x[99];
  std::shared_ptr<BigBoi[]> p8 = std::make_shared_for_overwrite<BigBoi[]>(11);
  (void) p8[0].x[0];
  (void) p8[10].x[10];
}

void
test03()
{
  // Type with non-trivial initialization should still be default-initialized.
  struct NonTriv
  {
    int init = 0xbb;
    int uninit;
  };
  std::shared_ptr<NonTriv> a = std::make_shared_for_overwrite<NonTriv>();
  VERIFY( a->init == 0xbb );
  std::shared_ptr<NonTriv[]> b = std::make_shared_for_overwrite<NonTriv[2]>();
  VERIFY( b[1].init == 0xbb );
  std::shared_ptr<NonTriv[]> c = std::make_shared_for_overwrite<NonTriv[]>(2);
  VERIFY( c[1].init == 0xbb );
}

int
main()
{
  test01();
  test02();
  test03();
}