1 //===----------------------------------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // XFAIL: libcpp-no-exceptions
11 // UNSUPPORTED: libcpp-has-no-threads
12 
13 // <thread>
14 
15 // class thread
16 
17 // template <class F, class ...Args> thread(F&& f, Args&&... args);
18 
19 // UNSUPPORTED: sanitizer-new-delete
20 
21 #include <thread>
22 #include <new>
23 #include <atomic>
24 #include <cstdlib>
25 #include <cassert>
26 
27 #include "test_macros.h"
28 
29 std::atomic<unsigned> throw_one(0xFFFF);
30 std::atomic<unsigned> outstanding_new(0);
31 
32 
33 void* operator new(std::size_t s) throw(std::bad_alloc)
34 {
35     if (throw_one == 0)
36         throw std::bad_alloc();
37     --throw_one;
38     ++outstanding_new;
39     void* ret = std::malloc(s);
40     if (!ret) std::abort(); // placate MSVC's unchecked malloc warning
41     return ret;
42 }
43 
44 void  operator delete(void* p) throw()
45 {
46     --outstanding_new;
47     std::free(p);
48 }
49 
50 bool f_run = false;
51 
52 void f()
53 {
54     f_run = true;
55 }
56 
57 class G
58 {
59     int alive_;
60 public:
61     static int n_alive;
62     static bool op_run;
63 
64     G() : alive_(1) {++n_alive;}
65     G(const G& g) : alive_(g.alive_) {++n_alive;}
66     ~G() {alive_ = 0; --n_alive;}
67 
68     void operator()()
69     {
70         assert(alive_ == 1);
71         assert(n_alive >= 1);
72         op_run = true;
73     }
74 
75     void operator()(int i, double j)
76     {
77         assert(alive_ == 1);
78         assert(n_alive >= 1);
79         assert(i == 5);
80         assert(j == 5.5);
81         op_run = true;
82     }
83 };
84 
85 int G::n_alive = 0;
86 bool G::op_run = false;
87 
88 #if TEST_STD_VER >= 11
89 
90 class MoveOnly
91 {
92     MoveOnly(const MoveOnly&);
93 public:
94     MoveOnly() {}
95     MoveOnly(MoveOnly&&) {}
96 
97     void operator()(MoveOnly&&)
98     {
99     }
100 };
101 
102 #endif
103 
104 // Test throwing std::bad_alloc
105 //-----------------------------
106 // Concerns:
107 //  A Each allocation performed during thread construction should be performed
108 //    in the parent thread so that std::terminate is not called if
109 //    std::bad_alloc is thrown by new.
110 //  B std::threads constructor should properly handle exceptions and not leak
111 //    memory.
112 // Plan:
113 //  1 Create a thread and count the number of allocations, 'N', it performs.
114 //  2 For each allocation performed run a test where that allocation throws.
115 //    2.1 check that the exception can be caught in the parent thread.
116 //    2.2 Check that the functor has not been called.
117 //    2.3 Check that no memory allocated by the creation of the thread is leaked.
118 //  3 Finally check that a thread runs successfully if we throw after 'N+1'
119 //    allocations.
120 void test_throwing_new_during_thread_creation() {
121     throw_one = 0xFFF;
122     {
123         std::thread t(f);
124         t.join();
125     }
126     const int numAllocs = 0xFFF - throw_one;
127     // i <= numAllocs means the last iteration is expected not to throw.
128     for (int i=0; i <= numAllocs; ++i) {
129         throw_one = i;
130         f_run = false;
131         unsigned old_outstanding = outstanding_new;
132         try {
133             std::thread t(f);
134             assert(i == numAllocs); // Only final iteration will not throw.
135             t.join();
136             assert(f_run);
137         } catch (std::bad_alloc const&) {
138             assert(i < numAllocs);
139             assert(!f_run); // (2.2)
140         }
141         assert(old_outstanding == outstanding_new); // (2.3)
142     }
143     f_run = false;
144     throw_one = 0xFFF;
145 }
146 
147 int main()
148 {
149     test_throwing_new_during_thread_creation();
150     {
151         std::thread t(f);
152         t.join();
153         assert(f_run == true);
154     }
155 
156     {
157         assert(G::n_alive == 0);
158         assert(!G::op_run);
159         std::thread t((G()));
160         t.join();
161         assert(G::n_alive == 0);
162         assert(G::op_run);
163     }
164     G::op_run = false;
165     {
166         try
167         {
168             throw_one = 0;
169             assert(G::n_alive == 0);
170             assert(!G::op_run);
171             std::thread t((G()));
172             assert(false);
173         }
174         catch (...)
175         {
176             throw_one = 0xFFFF;
177             assert(G::n_alive == 0);
178             assert(!G::op_run);
179         }
180     }
181 #if TEST_STD_VER >= 11
182     {
183         assert(G::n_alive == 0);
184         assert(!G::op_run);
185         std::thread t(G(), 5, 5.5);
186         t.join();
187         assert(G::n_alive == 0);
188         assert(G::op_run);
189     }
190     {
191         std::thread t = std::thread(MoveOnly(), MoveOnly());
192         t.join();
193     }
194 #endif
195 }
196