libstdc++
throw_allocator.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 
3 // Copyright (C) 2005-2013 Free Software Foundation, Inc.
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 3, 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 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 // Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
26 
27 // Permission to use, copy, modify, sell, and distribute this software
28 // is hereby granted without fee, provided that the above copyright
29 // notice appears in all copies, and that both that copyright notice
30 // and this permission notice appear in supporting documentation. None
31 // of the above authors, nor IBM Haifa Research Laboratories, make any
32 // representation about the suitability of this software for any
33 // purpose. It is provided "as is" without express or implied
34 // warranty.
35 
36 /** @file ext/throw_allocator.h
37  * This file is a GNU extension to the Standard C++ Library.
38  *
39  * Contains two exception-generating types (throw_value, throw_allocator)
40  * intended to be used as value and allocator types while testing
41  * exception safety in templatized containers and algorithms. The
42  * allocator has additional log and debug features. The exception
43  * generated is of type forced_exception_error.
44  */
45 
46 #ifndef _THROW_ALLOCATOR_H
47 #define _THROW_ALLOCATOR_H 1
48 
49 #include <cmath>
50 #include <ctime>
51 #include <map>
52 #include <string>
53 #include <ostream>
54 #include <stdexcept>
55 #include <utility>
56 #include <bits/functexcept.h>
57 #include <bits/move.h>
58 #if __cplusplus >= 201103L
59 # include <functional>
60 # include <random>
61 #else
62 # include <tr1/functional>
63 # include <tr1/random>
64 #endif
65 
66 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
67 {
68 _GLIBCXX_BEGIN_NAMESPACE_VERSION
69 
70  /**
71  * @brief Thown by exception safety machinery.
72  * @ingroup exceptions
73  */
74  struct forced_error : public std::exception
75  { };
76 
77  // Substitute for forced_error object when -fno-exceptions.
78  inline void
79  __throw_forced_error()
80  { _GLIBCXX_THROW_OR_ABORT(forced_error()); }
81 
82  /**
83  * @brief Base class for checking address and label information
84  * about allocations. Create a std::map between the allocated
85  * address (void*) and a datum for annotations, which are a pair of
86  * numbers corresponding to label and allocated size.
87  */
89  {
91  {
92  label();
93  map();
94  }
95 
96  static void
97  set_label(size_t l)
98  { label() = l; }
99 
100  static size_t
101  get_label()
102  { return label(); }
103 
104  void
105  insert(void* p, size_t size)
106  {
107  if (!p)
108  {
109  std::string error("annotate_base::insert null insert!\n");
110  log_to_string(error, make_entry(p, size));
111  std::__throw_logic_error(error.c_str());
112  }
113 
114  const_iterator found = map().find(p);
115  if (found != map().end())
116  {
117  std::string error("annotate_base::insert double insert!\n");
118  log_to_string(error, make_entry(p, size));
119  log_to_string(error, *found);
120  std::__throw_logic_error(error.c_str());
121  }
122 
123  map().insert(make_entry(p, size));
124  }
125 
126  void
127  erase(void* p, size_t size)
128  {
129  check_allocated(p, size);
130  map().erase(p);
131  }
132 
133  // See if a particular address and allocation size has been saved.
134  inline void
135  check_allocated(void* p, size_t size)
136  {
137  const_iterator found = map().find(p);
138  if (found == map().end())
139  {
140  std::string error("annotate_base::check_allocated by value "
141  "null erase!\n");
142  log_to_string(error, make_entry(p, size));
143  std::__throw_logic_error(error.c_str());
144  }
145 
146  if (found->second.second != size)
147  {
148  std::string error("annotate_base::check_allocated by value "
149  "wrong-size erase!\n");
150  log_to_string(error, make_entry(p, size));
151  log_to_string(error, *found);
152  std::__throw_logic_error(error.c_str());
153  }
154  }
155 
156  // See if a given label has been allocated.
157  inline void
158  check_allocated(size_t label)
159  {
160  const_iterator beg = map().begin();
161  const_iterator end = map().end();
162  std::string found;
163  while (beg != end)
164  {
165  if (beg->second.first == label)
166  log_to_string(found, *beg);
167  ++beg;
168  }
169 
170  if (!found.empty())
171  {
172  std::string error("annotate_base::check_allocated by label\n");
173  error += found;
174  std::__throw_logic_error(error.c_str());
175  }
176  }
177 
178  private:
182  typedef map_type::const_iterator const_iterator;
183  typedef map_type::const_reference const_reference;
184 
185  friend std::ostream&
186  operator<<(std::ostream&, const annotate_base&);
187 
188  entry_type
189  make_entry(void* p, size_t size)
190  { return std::make_pair(p, data_type(get_label(), size)); }
191 
192  void
193  log_to_string(std::string& s, const_reference ref) const
194  {
195  char buf[40];
196  const char tab('\t');
197  s += "label: ";
198  unsigned long l = static_cast<unsigned long>(ref.second.first);
199  __builtin_sprintf(buf, "%lu", l);
200  s += buf;
201  s += tab;
202  s += "size: ";
203  l = static_cast<unsigned long>(ref.second.second);
204  __builtin_sprintf(buf, "%lu", l);
205  s += buf;
206  s += tab;
207  s += "address: ";
208  __builtin_sprintf(buf, "%p", ref.first);
209  s += buf;
210  s += '\n';
211  }
212 
213  static size_t&
214  label()
215  {
216  static size_t _S_label(std::numeric_limits<size_t>::max());
217  return _S_label;
218  }
219 
220  static map_type&
221  map()
222  {
223  static map_type _S_map;
224  return _S_map;
225  }
226  };
227 
228  inline std::ostream&
229  operator<<(std::ostream& os, const annotate_base& __b)
230  {
231  std::string error;
232  typedef annotate_base base_type;
233  base_type::const_iterator beg = __b.map().begin();
234  base_type::const_iterator end = __b.map().end();
235  for (; beg != end; ++beg)
236  __b.log_to_string(error, *beg);
237  return os << error;
238  }
239 
240 
241  /**
242  * @brief Base struct for condition policy.
243  *
244  * Requires a public member function with the signature
245  * void throw_conditionally()
246  */
248  {
249  virtual ~condition_base() { };
250  };
251 
252 
253  /**
254  * @brief Base class for incremental control and throw.
255  */
257  {
258  // Scope-level adjustor objects: set limit for throw at the
259  // beginning of a scope block, and restores to previous limit when
260  // object is destroyed on exiting the block.
261  struct adjustor_base
262  {
263  private:
264  const size_t _M_orig;
265 
266  public:
267  adjustor_base() : _M_orig(limit()) { }
268 
269  virtual
270  ~adjustor_base() { set_limit(_M_orig); }
271  };
272 
273  /// Never enter the condition.
274  struct never_adjustor : public adjustor_base
275  {
277  };
278 
279  /// Always enter the condition.
280  struct always_adjustor : public adjustor_base
281  {
282  always_adjustor() { set_limit(count()); }
283  };
284 
285  /// Enter the nth condition.
286  struct limit_adjustor : public adjustor_base
287  {
288  limit_adjustor(const size_t __l) { set_limit(__l); }
289  };
290 
291  // Increment _S_count every time called.
292  // If _S_count matches the limit count, throw.
293  static void
294  throw_conditionally()
295  {
296  if (count() == limit())
297  __throw_forced_error();
298  ++count();
299  }
300 
301  static size_t&
302  count()
303  {
304  static size_t _S_count(0);
305  return _S_count;
306  }
307 
308  static size_t&
309  limit()
310  {
311  static size_t _S_limit(std::numeric_limits<size_t>::max());
312  return _S_limit;
313  }
314 
315  // Zero the throw counter, set limit to argument.
316  static void
317  set_limit(const size_t __l)
318  {
319  limit() = __l;
320  count() = 0;
321  }
322  };
323 
324 
325  /**
326  * @brief Base class for random probability control and throw.
327  */
329  {
330  // Scope-level adjustor objects: set probability for throw at the
331  // beginning of a scope block, and restores to previous
332  // probability when object is destroyed on exiting the block.
333  struct adjustor_base
334  {
335  private:
336  const double _M_orig;
337 
338  public:
339  adjustor_base() : _M_orig(probability()) { }
340 
341  virtual ~adjustor_base()
342  { set_probability(_M_orig); }
343  };
344 
345  /// Group condition.
346  struct group_adjustor : public adjustor_base
347  {
348  group_adjustor(size_t size)
349  { set_probability(1 - std::pow(double(1 - probability()),
350  double(0.5 / (size + 1))));
351  }
352  };
353 
354  /// Never enter the condition.
355  struct never_adjustor : public adjustor_base
356  {
357  never_adjustor() { set_probability(0); }
358  };
359 
360  /// Always enter the condition.
361  struct always_adjustor : public adjustor_base
362  {
363  always_adjustor() { set_probability(1); }
364  };
365 
367  {
368  probability();
369  engine();
370  }
371 
372  static void
373  set_probability(double __p)
374  { probability() = __p; }
375 
376  static void
377  throw_conditionally()
378  {
379  if (generate() < probability())
380  __throw_forced_error();
381  }
382 
383  void
384  seed(unsigned long __s)
385  { engine().seed(__s); }
386 
387  private:
388 #if __cplusplus >= 201103L
389  typedef std::uniform_real_distribution<double> distribution_type;
390  typedef std::mt19937 engine_type;
391 #else
392  typedef std::tr1::uniform_real<double> distribution_type;
393  typedef std::tr1::mt19937 engine_type;
394 #endif
395 
396  static double
397  generate()
398  {
399 #if __cplusplus >= 201103L
400  const distribution_type distribution(0, 1);
401  static auto generator = std::bind(distribution, engine());
402 #else
403  // Use variate_generator to get normalized results.
404  typedef std::tr1::variate_generator<engine_type, distribution_type> gen_t;
405  distribution_type distribution(0, 1);
406  static gen_t generator(engine(), distribution);
407 #endif
408 
409  double random = generator();
410  if (random < distribution.min() || random > distribution.max())
411  {
412  std::string __s("random_condition::generate");
413  __s += "\n";
414  __s += "random number generated is: ";
415  char buf[40];
416  __builtin_sprintf(buf, "%f", random);
417  __s += buf;
418  std::__throw_out_of_range(__s.c_str());
419  }
420 
421  return random;
422  }
423 
424  static double&
425  probability()
426  {
427  static double _S_p;
428  return _S_p;
429  }
430 
431  static engine_type&
432  engine()
433  {
434  static engine_type _S_e;
435  return _S_e;
436  }
437  };
438 
439 
440  /**
441  * @brief Class with exception generation control. Intended to be
442  * used as a value_type in templatized code.
443  *
444  * Note: Destructor not allowed to throw.
445  */
446  template<typename _Cond>
447  struct throw_value_base : public _Cond
448  {
449  typedef _Cond condition_type;
450 
451  using condition_type::throw_conditionally;
452 
453  std::size_t _M_i;
454 
455 #ifndef _GLIBCXX_IS_AGGREGATE
456  throw_value_base() : _M_i(0)
457  { throw_conditionally(); }
458 
459  throw_value_base(const throw_value_base& __v) : _M_i(__v._M_i)
460  { throw_conditionally(); }
461 
462 #if __cplusplus >= 201103L
463  // Shall not throw.
464  throw_value_base(throw_value_base&&) = default;
465 #endif
466 
467  explicit throw_value_base(const std::size_t __i) : _M_i(__i)
468  { throw_conditionally(); }
469 #endif
470 
472  operator=(const throw_value_base& __v)
473  {
474  throw_conditionally();
475  _M_i = __v._M_i;
476  return *this;
477  }
478 
479 #if __cplusplus >= 201103L
480  // Shall not throw.
482  operator=(throw_value_base&&) = default;
483 #endif
484 
486  operator++()
487  {
488  throw_conditionally();
489  ++_M_i;
490  return *this;
491  }
492  };
493 
494  template<typename _Cond>
495  inline void
497  {
498  typedef throw_value_base<_Cond> throw_value;
499  throw_value::throw_conditionally();
500  throw_value orig(__a);
501  __a = __b;
502  __b = orig;
503  }
504 
505  // General instantiable types requirements.
506  template<typename _Cond>
507  inline bool
508  operator==(const throw_value_base<_Cond>& __a,
509  const throw_value_base<_Cond>& __b)
510  {
511  typedef throw_value_base<_Cond> throw_value;
512  throw_value::throw_conditionally();
513  bool __ret = __a._M_i == __b._M_i;
514  return __ret;
515  }
516 
517  template<typename _Cond>
518  inline bool
519  operator<(const throw_value_base<_Cond>& __a,
520  const throw_value_base<_Cond>& __b)
521  {
522  typedef throw_value_base<_Cond> throw_value;
523  throw_value::throw_conditionally();
524  bool __ret = __a._M_i < __b._M_i;
525  return __ret;
526  }
527 
528  // Numeric algorithms instantiable types requirements.
529  template<typename _Cond>
530  inline throw_value_base<_Cond>
531  operator+(const throw_value_base<_Cond>& __a,
532  const throw_value_base<_Cond>& __b)
533  {
534  typedef throw_value_base<_Cond> throw_value;
535  throw_value::throw_conditionally();
536  throw_value __ret(__a._M_i + __b._M_i);
537  return __ret;
538  }
539 
540  template<typename _Cond>
541  inline throw_value_base<_Cond>
542  operator-(const throw_value_base<_Cond>& __a,
543  const throw_value_base<_Cond>& __b)
544  {
545  typedef throw_value_base<_Cond> throw_value;
546  throw_value::throw_conditionally();
547  throw_value __ret(__a._M_i - __b._M_i);
548  return __ret;
549  }
550 
551  template<typename _Cond>
552  inline throw_value_base<_Cond>
553  operator*(const throw_value_base<_Cond>& __a,
554  const throw_value_base<_Cond>& __b)
555  {
556  typedef throw_value_base<_Cond> throw_value;
557  throw_value::throw_conditionally();
558  throw_value __ret(__a._M_i * __b._M_i);
559  return __ret;
560  }
561 
562 
563  /// Type throwing via limit condition.
564  struct throw_value_limit : public throw_value_base<limit_condition>
565  {
566  typedef throw_value_base<limit_condition> base_type;
567 
568 #ifndef _GLIBCXX_IS_AGGREGATE
569  throw_value_limit() { }
570 
571  throw_value_limit(const throw_value_limit& __other)
572  : base_type(__other._M_i) { }
573 
574 #if __cplusplus >= 201103L
576 #endif
577 
578  explicit throw_value_limit(const std::size_t __i) : base_type(__i) { }
579 #endif
580 
582  operator=(const throw_value_limit& __other)
583  {
584  base_type::operator=(__other);
585  return *this;
586  }
587 
588 #if __cplusplus >= 201103L
590  operator=(throw_value_limit&&) = default;
591 #endif
592  };
593 
594  /// Type throwing via random condition.
595  struct throw_value_random : public throw_value_base<random_condition>
596  {
597  typedef throw_value_base<random_condition> base_type;
598 
599 #ifndef _GLIBCXX_IS_AGGREGATE
600  throw_value_random() { }
601 
602  throw_value_random(const throw_value_random& __other)
603  : base_type(__other._M_i) { }
604 
605 #if __cplusplus >= 201103L
607 #endif
608 
609  explicit throw_value_random(const std::size_t __i) : base_type(__i) { }
610 #endif
611 
613  operator=(const throw_value_random& __other)
614  {
615  base_type::operator=(__other);
616  return *this;
617  }
618 
619 #if __cplusplus >= 201103L
621  operator=(throw_value_random&&) = default;
622 #endif
623  };
624 
625 
626  /**
627  * @brief Allocator class with logging and exception generation control.
628  * Intended to be used as an allocator_type in templatized code.
629  * @ingroup allocators
630  *
631  * Note: Deallocate not allowed to throw.
632  */
633  template<typename _Tp, typename _Cond>
635  : public annotate_base, public _Cond
636  {
637  public:
638  typedef size_t size_type;
639  typedef ptrdiff_t difference_type;
640  typedef _Tp value_type;
641  typedef value_type* pointer;
642  typedef const value_type* const_pointer;
643  typedef value_type& reference;
644  typedef const value_type& const_reference;
645 
646 #if __cplusplus >= 201103L
647  // _GLIBCXX_RESOLVE_LIB_DEFECTS
648  // 2103. std::allocator propagate_on_container_move_assignment
649  typedef std::true_type propagate_on_container_move_assignment;
650 #endif
651 
652  private:
653  typedef _Cond condition_type;
654 
655  std::allocator<value_type> _M_allocator;
656 
657  using condition_type::throw_conditionally;
658 
659  public:
660  size_type
661  max_size() const _GLIBCXX_USE_NOEXCEPT
662  { return _M_allocator.max_size(); }
663 
664  pointer
665  address(reference __x) const _GLIBCXX_NOEXCEPT
666  { return std::__addressof(__x); }
667 
668  const_pointer
669  address(const_reference __x) const _GLIBCXX_NOEXCEPT
670  { return std::__addressof(__x); }
671 
672  pointer
673  allocate(size_type __n, std::allocator<void>::const_pointer hint = 0)
674  {
675  if (__n > this->max_size())
676  std::__throw_bad_alloc();
677 
678  throw_conditionally();
679  pointer const a = _M_allocator.allocate(__n, hint);
680  insert(a, sizeof(value_type) * __n);
681  return a;
682  }
683 
684 #if __cplusplus >= 201103L
685  template<typename _Up, typename... _Args>
686  void
687  construct(_Up* __p, _Args&&... __args)
688  { return _M_allocator.construct(__p, std::forward<_Args>(__args)...); }
689 
690  template<typename _Up>
691  void
692  destroy(_Up* __p)
693  { _M_allocator.destroy(__p); }
694 #else
695  void
696  construct(pointer __p, const value_type& val)
697  { return _M_allocator.construct(__p, val); }
698 
699  void
700  destroy(pointer __p)
701  { _M_allocator.destroy(__p); }
702 #endif
703 
704  void
705  deallocate(pointer __p, size_type __n)
706  {
707  erase(__p, sizeof(value_type) * __n);
708  _M_allocator.deallocate(__p, __n);
709  }
710 
711  void
712  check_allocated(pointer __p, size_type __n)
713  {
714  size_type __t = sizeof(value_type) * __n;
715  annotate_base::check_allocated(__p, __t);
716  }
717 
718  void
719  check_allocated(size_type __n)
720  { annotate_base::check_allocated(__n); }
721  };
722 
723  template<typename _Tp, typename _Cond>
724  inline bool
725  operator==(const throw_allocator_base<_Tp, _Cond>&,
727  { return true; }
728 
729  template<typename _Tp, typename _Cond>
730  inline bool
731  operator!=(const throw_allocator_base<_Tp, _Cond>&,
732  const throw_allocator_base<_Tp, _Cond>&)
733  { return false; }
734 
735  /// Allocator throwing via limit condition.
736  template<typename _Tp>
738  : public throw_allocator_base<_Tp, limit_condition>
739  {
740  template<typename _Tp1>
741  struct rebind
742  { typedef throw_allocator_limit<_Tp1> other; };
743 
744  throw_allocator_limit() _GLIBCXX_USE_NOEXCEPT { }
745 
747  _GLIBCXX_USE_NOEXCEPT { }
748 
749  template<typename _Tp1>
751  _GLIBCXX_USE_NOEXCEPT { }
752 
753  ~throw_allocator_limit() _GLIBCXX_USE_NOEXCEPT { }
754  };
755 
756  /// Allocator throwing via random condition.
757  template<typename _Tp>
759  : public throw_allocator_base<_Tp, random_condition>
760  {
761  template<typename _Tp1>
762  struct rebind
763  { typedef throw_allocator_random<_Tp1> other; };
764 
765  throw_allocator_random() _GLIBCXX_USE_NOEXCEPT { }
766 
768  _GLIBCXX_USE_NOEXCEPT { }
769 
770  template<typename _Tp1>
772  _GLIBCXX_USE_NOEXCEPT { }
773 
774  ~throw_allocator_random() _GLIBCXX_USE_NOEXCEPT { }
775  };
776 
777 _GLIBCXX_END_NAMESPACE_VERSION
778 } // namespace
779 
780 #if __cplusplus >= 201103L
781 
782 # include <bits/functional_hash.h>
783 
784 namespace std _GLIBCXX_VISIBILITY(default)
785 {
786  /// Explicit specialization of std::hash for __gnu_cxx::throw_value_limit.
787  template<>
788  struct hash<__gnu_cxx::throw_value_limit>
789  : public std::unary_function<__gnu_cxx::throw_value_limit, size_t>
790  {
791  size_t
792  operator()(const __gnu_cxx::throw_value_limit& __val) const
793  {
795  size_t __result = __h(__val._M_i);
796  return __result;
797  }
798  };
799 
800  /// Explicit specialization of std::hash for __gnu_cxx::throw_value_limit.
801  template<>
802  struct hash<__gnu_cxx::throw_value_random>
803  : public std::unary_function<__gnu_cxx::throw_value_random, size_t>
804  {
805  size_t
806  operator()(const __gnu_cxx::throw_value_random& __val) const
807  {
809  size_t __result = __h(__val._M_i);
810  return __result;
811  }
812  };
813 } // end namespace std
814 #endif
815 
816 #endif
Allocator class with logging and exception generation control. Intended to be used as an allocator_ty...
mersenne_twister_engine< uint_fast32_t, 32, 624, 397, 31, 0x9908b0dfUL, 11, 0xffffffffUL, 7, 0x9d2c5680UL, 15, 0xefc60000UL, 18, 1812433253UL > mt19937
Definition: random.h:1543
const _CharT * c_str() const noexcept
Return const pointer to null-terminated contents.
Base class for checking address and label information about allocations. Create a std::map between th...
Class with exception generation control. Intended to be used as a value_type in templatized code...
const _Tp & max(const _Tp &, const _Tp &)
This does what you think it does.
Definition: stl_algobase.h:216
auto end(_Container &__cont) -> decltype(__cont.end())
Return an iterator pointing to one past the last element of the container.
Definition: range_access.h:68
GNU extensions for public use.
_Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:47
Base class for incremental control and throw.
Thown by exception safety machinery.
Uniform continuous distribution for random numbers.
Definition: random.h:1867
iterator begin() noexcept
Definition: stl_map.h:320
constexpr pair< typename __decay_and_strip< _T1 >::__type, typename __decay_and_strip< _T2 >::__type > make_pair(_T1 &&__x, _T2 &&__y)
A convenience wrapper for creating a pair from two objects.
Definition: stl_pair.h:276
ISO C++ entities toplevel namespace is std.
Type throwing via random condition.
Allocator throwing via random condition.
iterator find(const key_type &__x)
Tries to locate an element in a map.
Definition: stl_map.h:821
A standard container made up of (key,value) pairs, which can be retrieved based on a key...
Definition: stl_map.h:96
Base class for random probability control and throw.
basic_string< _CharT, _Traits, _Alloc > operator+(const basic_string< _CharT, _Traits, _Alloc > &__lhs, const basic_string< _CharT, _Traits, _Alloc > &__rhs)
Concatenate two strings.
Allocator throwing via limit condition.
Type throwing via limit condition.
bool empty() const noexcept
Definition: basic_string.h:811
Primary class template hash.
std::pair< iterator, bool > insert(const value_type &__x)
Attempts to insert a std::pair into the map.
Definition: stl_map.h:594
Struct holding two objects of arbitrary type.
Definition: stl_pair.h:96
iterator erase(const_iterator __position)
Erases an element from a map.
Definition: stl_map.h:690
iterator end() noexcept
Definition: stl_map.h:338
Base struct for condition policy.