]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/include/ext/throw_allocator.h
re PR testsuite/39696 (gcc.dg/tree-ssa/ssa-ccp-25.c scan-tree-dump doesn't work on...
[thirdparty/gcc.git] / libstdc++-v3 / include / ext / throw_allocator.h
CommitLineData
a86151e1
BK
1// -*- C++ -*-
2
5b9daa7e 3// Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
a86151e1
BK
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the terms
7// of the GNU General Public License as published by the Free Software
8// Foundation; either version 2, or (at your option) any later
9// version.
10
11// This library is distributed in the hope that it will be useful, but
12// WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this library; see the file COPYING. If not, write to
18// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
19// MA 02111-1307, USA.
20
21// As a special exception, you may use this file as part of a free
22// software library without restriction. Specifically, if other files
23// instantiate templates or use macros or inline functions from this
24// file, or you compile this file and link it with other files to
25// produce an executable, this file does not by itself cause the
26// resulting executable to be covered by the GNU General Public
27// License. This exception does not however invalidate any other
28// reasons why the executable file might be covered by the GNU General
29// Public License.
30
31// Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
32
33// Permission to use, copy, modify, sell, and distribute this software
34// is hereby granted without fee, provided that the above copyright
35// notice appears in all copies, and that both that copyright notice
36// and this permission notice appear in supporting documentation. None
37// of the above authors, nor IBM Haifa Research Laboratories, make any
38// representation about the suitability of this software for any
39// purpose. It is provided "as is" without express or implied
40// warranty.
41
65be6ddd 42/** @file ext/throw_allocator.h
78a53887
BK
43 * This file is a GNU extension to the Standard C++ Library.
44 *
45 * Contains an exception-throwing allocator, useful for testing
46 * exception safety. In addition, allocation addresses are stored and
47 * sanity checked.
48 */
49
a86151e1
BK
50#ifndef _THROW_ALLOCATOR_H
51#define _THROW_ALLOCATOR_H 1
52
53#include <cmath>
67a7356b 54#include <ctime>
a86151e1
BK
55#include <map>
56#include <set>
57#include <string>
58#include <ostream>
59#include <stdexcept>
60#include <utility>
61#include <tr1/random>
949d9ae1 62#include <bits/functexcept.h>
ca0f8fd1 63#include <bits/move.h>
a86151e1
BK
64
65_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
66
67 class twister_rand_gen
2e3f9c21
BK
68 {
69 private:
70 std::tr1::mt19937 _M_generator;
71
a86151e1 72 public:
2e3f9c21 73 twister_rand_gen(unsigned int s = static_cast<unsigned int>(std::time(0)));
a86151e1
BK
74
75 void
76 init(unsigned int);
77
78 double
79 get_prob();
a86151e1
BK
80 };
81
5b9daa7e
BK
82 /**
83 * @brief Thown by throw_allocator.
84 * @ingroup exceptions
85 */
a86151e1
BK
86 struct forced_exception_error : public std::exception
87 { };
88
949d9ae1
BK
89 // Substitute for concurrence_error object in the case of -fno-exceptions.
90 inline void
91 __throw_forced_exception_error()
92 {
93#if __EXCEPTIONS
94 throw forced_exception_error();
95#else
96 __builtin_abort();
97#endif
98 }
99
939759fc 100 /// Base class.
a86151e1
BK
101 class throw_allocator_base
102 {
103 public:
104 void
105 init(unsigned long seed);
106
107 static void
108 set_throw_prob(double throw_prob);
109
110 static double
111 get_throw_prob();
112
113 static void
114 set_label(size_t l);
115
116 static bool
117 empty();
118
119 struct group_throw_prob_adjustor
120 {
2e3f9c21 121 group_throw_prob_adjustor(size_t size) : _M_throw_prob_orig(_S_throw_prob)
a86151e1
BK
122 {
123 _S_throw_prob =
113008b5 124 1 - std::pow(double(1 - _S_throw_prob), double(0.5 / (size + 1)));
a86151e1
BK
125 }
126
127 ~group_throw_prob_adjustor()
128 { _S_throw_prob = _M_throw_prob_orig; }
129
130 private:
131 const double _M_throw_prob_orig;
132 };
133
134 struct zero_throw_prob_adjustor
135 {
136 zero_throw_prob_adjustor() : _M_throw_prob_orig(_S_throw_prob)
137 { _S_throw_prob = 0; }
138
139 ~zero_throw_prob_adjustor()
140 { _S_throw_prob = _M_throw_prob_orig; }
141
142 private:
143 const double _M_throw_prob_orig;
144 };
145
146 protected:
147 static void
148 insert(void*, size_t);
149
150 static void
151 erase(void*, size_t);
152
153 static void
154 throw_conditionally();
155
3441f106
BK
156 // See if a particular address and size has been allocated by this
157 // allocator.
a86151e1 158 static void
3441f106 159 check_allocated(void*, size_t);
a86151e1 160
3441f106 161 // See if a given label has been allocated by this allocator.
a86151e1 162 static void
3441f106 163 check_allocated(size_t);
a86151e1
BK
164
165 private:
166 typedef std::pair<size_t, size_t> alloc_data_type;
167 typedef std::map<void*, alloc_data_type> map_type;
168 typedef map_type::value_type entry_type;
169 typedef map_type::const_iterator const_iterator;
170 typedef map_type::const_reference const_reference;
171
172 friend std::ostream&
173 operator<<(std::ostream&, const throw_allocator_base&);
174
175 static entry_type
176 make_entry(void*, size_t);
177
178 static void
179 print_to_string(std::string&);
180
181 static void
182 print_to_string(std::string&, const_reference);
183
184 static twister_rand_gen _S_g;
185 static map_type _S_map;
186 static double _S_throw_prob;
187 static size_t _S_label;
188 };
189
5b9daa7e
BK
190 /**
191 * @brief Allocator class with logging and exception control.
192 * @ingroup allocators
193 */
a86151e1
BK
194 template<typename T>
195 class throw_allocator : public throw_allocator_base
196 {
197 public:
3441f106
BK
198 typedef size_t size_type;
199 typedef ptrdiff_t difference_type;
200 typedef T value_type;
201 typedef value_type* pointer;
202 typedef const value_type* const_pointer;
203 typedef value_type& reference;
204 typedef const value_type& const_reference;
205
a86151e1
BK
206
207 template<typename U>
208 struct rebind
209 {
210 typedef throw_allocator<U> other;
211 };
212
213 throw_allocator() throw() { }
214
3441f106 215 throw_allocator(const throw_allocator&) throw() { }
a86151e1 216
3441f106 217 template<typename U>
a86151e1
BK
218 throw_allocator(const throw_allocator<U>&) throw() { }
219
220 ~throw_allocator() throw() { }
221
222 size_type
223 max_size() const throw()
3441f106 224 { return std::allocator<value_type>().max_size(); }
a86151e1
BK
225
226 pointer
b8637750 227 allocate(size_type __n, std::allocator<void>::const_pointer hint = 0)
a86151e1 228 {
b8637750
BK
229 if (__builtin_expect(__n > this->max_size(), false))
230 std::__throw_bad_alloc();
231
a86151e1 232 throw_conditionally();
b8637750
BK
233 value_type* const a = std::allocator<value_type>().allocate(__n, hint);
234 insert(a, sizeof(value_type) * __n);
a86151e1
BK
235 return a;
236 }
237
238 void
b8637750
BK
239 construct(pointer __p, const T& val)
240 { return std::allocator<value_type>().construct(__p, val); }
a86151e1 241
61fcb9fb
PC
242#ifdef __GXX_EXPERIMENTAL_CXX0X__
243 template<typename... _Args>
244 void
245 construct(pointer __p, _Args&&... __args)
246 {
247 return std::allocator<value_type>().
248 construct(__p, std::forward<_Args>(__args)...);
249 }
250#endif
251
a86151e1 252 void
b8637750
BK
253 destroy(pointer __p)
254 { std::allocator<value_type>().destroy(__p); }
a86151e1
BK
255
256 void
b8637750 257 deallocate(pointer __p, size_type __n)
a86151e1 258 {
b8637750
BK
259 erase(__p, sizeof(value_type) * __n);
260 std::allocator<value_type>().deallocate(__p, __n);
a86151e1
BK
261 }
262
263 void
b8637750
BK
264 check_allocated(pointer __p, size_type __n)
265 { throw_allocator_base::check_allocated(__p, sizeof(value_type) * __n); }
3441f106
BK
266
267 void
268 check_allocated(size_type label)
269 { throw_allocator_base::check_allocated(label); }
a86151e1
BK
270 };
271
272 template<typename T>
273 inline bool
274 operator==(const throw_allocator<T>&, const throw_allocator<T>&)
275 { return true; }
276
277 template<typename T>
278 inline bool
279 operator!=(const throw_allocator<T>&, const throw_allocator<T>&)
280 { return false; }
281
282 std::ostream&
283 operator<<(std::ostream& os, const throw_allocator_base& alloc)
284 {
285 std::string error;
286 throw_allocator_base::print_to_string(error);
287 os << error;
288 return os;
289 }
290
291 // XXX Should be in .cc.
292 twister_rand_gen::
293 twister_rand_gen(unsigned int seed) : _M_generator(seed) { }
294
295 void
296 twister_rand_gen::
297 init(unsigned int seed)
298 { _M_generator.seed(seed); }
299
300 double
301 twister_rand_gen::
302 get_prob()
303 {
2e3f9c21
BK
304 const double min = _M_generator.min();
305 const double res = static_cast<const double>(_M_generator() - min);
306 const double range = static_cast<const double>(_M_generator.max() - min);
307 const double ret = res / range;
a86151e1
BK
308 _GLIBCXX_DEBUG_ASSERT(ret >= 0 && ret <= 1);
309 return ret;
310 }
311
312 twister_rand_gen throw_allocator_base::_S_g;
313
939759fc 314 throw_allocator_base::map_type
a86151e1
BK
315 throw_allocator_base::_S_map;
316
317 double throw_allocator_base::_S_throw_prob;
318
319 size_t throw_allocator_base::_S_label = 0;
320
321 throw_allocator_base::entry_type
322 throw_allocator_base::make_entry(void* p, size_t size)
323 { return std::make_pair(p, alloc_data_type(_S_label, size)); }
324
325 void
326 throw_allocator_base::init(unsigned long seed)
327 { _S_g.init(seed); }
328
329 void
330 throw_allocator_base::set_throw_prob(double throw_prob)
331 { _S_throw_prob = throw_prob; }
332
333 double
334 throw_allocator_base::get_throw_prob()
335 { return _S_throw_prob; }
336
337 void
338 throw_allocator_base::set_label(size_t l)
339 { _S_label = l; }
340
341 void
342 throw_allocator_base::insert(void* p, size_t size)
343 {
344 const_iterator found_it = _S_map.find(p);
345 if (found_it != _S_map.end())
346 {
347 std::string error("throw_allocator_base::insert");
348 error += "double insert!";
349 error += '\n';
350 print_to_string(error, make_entry(p, size));
351 print_to_string(error, *found_it);
949d9ae1 352 std::__throw_logic_error(error.c_str());
a86151e1
BK
353 }
354 _S_map.insert(make_entry(p, size));
355 }
356
357 bool
358 throw_allocator_base::empty()
359 { return _S_map.empty(); }
360
361 void
362 throw_allocator_base::erase(void* p, size_t size)
363 {
364 check_allocated(p, size);
365 _S_map.erase(p);
366 }
367
368 void
369 throw_allocator_base::check_allocated(void* p, size_t size)
370 {
371 const_iterator found_it = _S_map.find(p);
372 if (found_it == _S_map.end())
373 {
3441f106 374 std::string error("throw_allocator_base::check_allocated by value ");
a86151e1
BK
375 error += "null erase!";
376 error += '\n';
377 print_to_string(error, make_entry(p, size));
949d9ae1 378 std::__throw_logic_error(error.c_str());
a86151e1
BK
379 }
380
381 if (found_it->second.second != size)
382 {
3441f106 383 std::string error("throw_allocator_base::check_allocated by value ");
a86151e1
BK
384 error += "wrong-size erase!";
385 error += '\n';
386 print_to_string(error, make_entry(p, size));
387 print_to_string(error, *found_it);
949d9ae1 388 std::__throw_logic_error(error.c_str());
a86151e1
BK
389 }
390 }
391
3441f106
BK
392 void
393 throw_allocator_base::check_allocated(size_t label)
394 {
395 std::string found;
396 const_iterator it = _S_map.begin();
397 while (it != _S_map.end())
398 {
399 if (it->second.first == label)
2e3f9c21
BK
400 {
401 print_to_string(found, *it);
402 }
3441f106
BK
403 ++it;
404 }
405
406 if (!found.empty())
407 {
408 std::string error("throw_allocator_base::check_allocated by label ");
409 error += '\n';
410 error += found;
949d9ae1 411 std::__throw_logic_error(error.c_str());
3441f106
BK
412 }
413 }
414
a86151e1
BK
415 void
416 throw_allocator_base::throw_conditionally()
417 {
418 if (_S_g.get_prob() < _S_throw_prob)
949d9ae1 419 __throw_forced_exception_error();
a86151e1
BK
420 }
421
422 void
423 throw_allocator_base::print_to_string(std::string& s)
424 {
3441f106
BK
425 const_iterator begin = throw_allocator_base::_S_map.begin();
426 const_iterator end = throw_allocator_base::_S_map.end();
427 for (; begin != end; ++begin)
428 print_to_string(s, *begin);
a86151e1
BK
429 }
430
431 void
432 throw_allocator_base::print_to_string(std::string& s, const_reference ref)
433 {
3441f106
BK
434 char buf[40];
435 const char tab('\t');
436 s += "address: ";
7919bb2f 437 __builtin_sprintf(buf, "%p", ref.first);
3441f106
BK
438 s += buf;
439 s += tab;
440 s += "label: ";
7919bb2f
PC
441 unsigned long l = static_cast<unsigned long>(ref.second.first);
442 __builtin_sprintf(buf, "%lu", l);
3441f106
BK
443 s += buf;
444 s += tab;
445 s += "size: ";
7919bb2f
PC
446 l = static_cast<unsigned long>(ref.second.second);
447 __builtin_sprintf(buf, "%lu", l);
3441f106 448 s += buf;
a86151e1
BK
449 s += '\n';
450 }
451
452_GLIBCXX_END_NAMESPACE
453
454#endif