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