throw_allocator.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
00004 // Free Software Foundation, Inc.
00005 //
00006 // This file is part of the GNU ISO C++ Library.  This library is free
00007 // software; you can redistribute it and/or modify it under the terms
00008 // of the GNU General Public License as published by the Free Software
00009 // Foundation; either version 3, or (at your option) any later
00010 // version.
00011 
00012 // This library is distributed in the hope that it will be useful, but
00013 // WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 // General Public License for more details.
00016 
00017 // Under Section 7 of GPL version 3, you are granted additional
00018 // permissions described in the GCC Runtime Library Exception, version
00019 // 3.1, as published by the Free Software Foundation.
00020 
00021 // You should have received a copy of the GNU General Public License and
00022 // a copy of the GCC Runtime Library Exception along with this program;
00023 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00024 // <http://www.gnu.org/licenses/>.
00025 
00026 // Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
00027 
00028 // Permission to use, copy, modify, sell, and distribute this software
00029 // is hereby granted without fee, provided that the above copyright
00030 // notice appears in all copies, and that both that copyright notice
00031 // and this permission notice appear in supporting documentation. None
00032 // of the above authors, nor IBM Haifa Research Laboratories, make any
00033 // representation about the suitability of this software for any
00034 // purpose. It is provided "as is" without express or implied
00035 // warranty.
00036 
00037 /** @file ext/throw_allocator.h
00038  *  This file is a GNU extension to the Standard C++ Library.
00039  *
00040  *  Contains two exception-generating types (throw_value, throw_allocator)
00041  *  intended to be used as value and allocator types while testing
00042  *  exception safety in templatized containers and algorithms. The
00043  *  allocator has additional log and debug features. The exception
00044  *  generated is of type forced_exception_error.
00045  */
00046 
00047 #ifndef _THROW_ALLOCATOR_H
00048 #define _THROW_ALLOCATOR_H 1
00049 
00050 #include <cmath>
00051 #include <ctime>
00052 #include <map>
00053 #include <string>
00054 #include <ostream>
00055 #include <stdexcept>
00056 #include <utility>
00057 #include <bits/functexcept.h>
00058 #include <bits/move.h>
00059 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00060 # include <functional>
00061 # include <random>
00062 #else
00063 # include <tr1/functional>
00064 # include <tr1/random>
00065 #endif
00066 
00067 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
00068 
00069   /**
00070    *  @brief Thown by exception safety machinery.
00071    *  @ingroup exceptions
00072    */
00073   struct forced_error : public std::exception
00074   { };
00075 
00076   // Substitute for forced_error object when -fno-exceptions.
00077   inline void
00078   __throw_forced_error()
00079   {
00080 #if __EXCEPTIONS
00081     throw forced_error();
00082 #else
00083     __builtin_abort();
00084 #endif
00085   }
00086 
00087 
00088   /**
00089    *  @brief Base class for checking address and label information
00090    *  about allocations. Create a std::map between the allocated
00091    *  address (void*) and a datum for annotations, which are a pair of
00092    *  numbers corresponding to label and allocated size.
00093    */
00094   struct annotate_base
00095   {
00096     annotate_base()
00097     {
00098       label();
00099       map();
00100     }
00101 
00102     static void
00103     set_label(size_t l)
00104     { label() = l; }
00105 
00106     static size_t
00107     get_label()
00108     { return label(); }
00109 
00110     void
00111     insert(void* p, size_t size)
00112     {
00113       if (p == NULL)
00114     {
00115       std::string error("annotate_base::insert null insert!\n");
00116       log_to_string(error, make_entry(p, size));
00117       std::__throw_logic_error(error.c_str());
00118     }
00119 
00120       const_iterator found = map().find(p);
00121       if (found != map().end())
00122     {
00123       std::string error("annotate_base::insert double insert!\n");
00124       log_to_string(error, make_entry(p, size));
00125       log_to_string(error, *found);
00126       std::__throw_logic_error(error.c_str());
00127     }
00128 
00129       map().insert(make_entry(p, size));
00130     }
00131 
00132     void
00133     erase(void* p, size_t size)
00134     {
00135       check_allocated(p, size);
00136       map().erase(p);
00137     }
00138 
00139     // See if a particular address and allocation size has been saved.
00140     inline void
00141     check_allocated(void* p, size_t size)
00142     {
00143       const_iterator found = map().find(p);
00144       if (found == map().end())
00145     {
00146       std::string error("annotate_base::check_allocated by value "
00147                 "null erase!\n");
00148       log_to_string(error, make_entry(p, size));
00149       std::__throw_logic_error(error.c_str());
00150     }
00151 
00152       if (found->second.second != size)
00153     {
00154       std::string error("annotate_base::check_allocated by value "
00155                 "wrong-size erase!\n");
00156       log_to_string(error, make_entry(p, size));
00157       log_to_string(error, *found);
00158       std::__throw_logic_error(error.c_str());
00159     }
00160     }
00161 
00162     // See if a given label has been allocated.
00163     inline void
00164     check_allocated(size_t label)
00165     {
00166       const_iterator beg = map().begin();
00167       const_iterator end = map().end();
00168       std::string found;
00169       while (beg != end)
00170     {
00171       if (beg->second.first == label)
00172         log_to_string(found, *beg);
00173       ++beg;
00174     }
00175 
00176       if (!found.empty())
00177     {
00178       std::string error("annotate_base::check_allocated by label\n");
00179       error += found;
00180       std::__throw_logic_error(error.c_str());
00181     }
00182     }
00183 
00184   private:
00185     typedef std::pair<size_t, size_t>       data_type;
00186     typedef std::map<void*, data_type>      map_type;
00187     typedef map_type::value_type        entry_type;
00188     typedef map_type::const_iterator        const_iterator;
00189     typedef map_type::const_reference       const_reference;
00190 
00191     friend std::ostream&
00192     operator<<(std::ostream&, const annotate_base&);
00193 
00194     entry_type
00195     make_entry(void* p, size_t size)
00196     { return std::make_pair(p, data_type(get_label(), size)); }
00197 
00198     void
00199     log_to_string(std::string& s, const_reference ref) const
00200     {
00201       char buf[40];
00202       const char tab('\t');
00203       s += "label: ";
00204       unsigned long l = static_cast<unsigned long>(ref.second.first);
00205       __builtin_sprintf(buf, "%lu", l);
00206       s += buf;
00207       s += tab;
00208       s += "size: ";
00209       l = static_cast<unsigned long>(ref.second.second);
00210       __builtin_sprintf(buf, "%lu", l);
00211       s += buf;
00212       s += tab;
00213       s += "address: ";
00214       __builtin_sprintf(buf, "%p", ref.first);
00215       s += buf;
00216       s += '\n';
00217     }
00218 
00219     static size_t&
00220     label()
00221     {
00222       static size_t _S_label(std::numeric_limits<size_t>::max());
00223       return _S_label;
00224     }
00225 
00226     static map_type&
00227     map()
00228     {
00229       static map_type _S_map;
00230       return _S_map;
00231     }
00232   };
00233 
00234   inline std::ostream&
00235   operator<<(std::ostream& os, const annotate_base& __b)
00236   {
00237     std::string error;
00238     typedef annotate_base base_type;
00239     base_type::const_iterator beg = __b.map().begin();
00240     base_type::const_iterator end = __b.map().end();
00241     for (; beg != end; ++beg)
00242       __b.log_to_string(error, *beg);
00243     return os << error;
00244   }
00245 
00246 
00247   /**
00248    *  @brief Base struct for condition policy.
00249    *
00250    * Requires a public member function with the signature
00251    * void throw_conditionally()
00252    */
00253   struct condition_base
00254   {
00255     virtual ~condition_base() { };
00256   };
00257 
00258 
00259   /**
00260    *  @brief Base class for incremental control and throw.
00261    */
00262   struct limit_condition : public condition_base
00263   {
00264     // Scope-level adjustor objects: set limit for throw at the
00265     // beginning of a scope block, and restores to previous limit when
00266     // object is destroyed on exiting the block.
00267     struct adjustor_base
00268     {
00269     private:
00270       const size_t _M_orig;
00271 
00272     public:
00273       adjustor_base() : _M_orig(limit()) { }
00274 
00275       virtual
00276       ~adjustor_base() { set_limit(_M_orig); }
00277     };
00278 
00279     /// Never enter the condition.
00280     struct never_adjustor : public adjustor_base
00281     {
00282       never_adjustor() { set_limit(std::numeric_limits<size_t>::max()); }
00283     };
00284 
00285     /// Always enter the condition.
00286     struct always_adjustor : public adjustor_base
00287     {
00288       always_adjustor() { set_limit(count()); }
00289     };
00290 
00291     /// Enter the nth condition.
00292     struct limit_adjustor : public adjustor_base
00293     {
00294       limit_adjustor(const size_t __l) { set_limit(__l); }
00295     };
00296 
00297     // Increment _S_count every time called.
00298     // If _S_count matches the limit count, throw.
00299     static void
00300     throw_conditionally()
00301     {
00302       if (count() == limit())
00303     __throw_forced_error();
00304       ++count();
00305     }
00306 
00307     static size_t&
00308     count()
00309     {
00310       static size_t _S_count(0);
00311       return _S_count;
00312     }
00313 
00314     static size_t&
00315     limit()
00316     {
00317       static size_t _S_limit(std::numeric_limits<size_t>::max());
00318       return _S_limit;
00319     }
00320 
00321     // Zero the throw counter, set limit to argument.
00322     static void
00323     set_limit(const size_t __l)
00324     {
00325       limit() = __l;
00326       count() = 0;
00327     }
00328   };
00329 
00330 
00331   /**
00332    *  @brief Base class for random probability control and throw.
00333    */
00334   struct random_condition : public condition_base
00335   {
00336     // Scope-level adjustor objects: set probability for throw at the
00337     // beginning of a scope block, and restores to previous
00338     // probability when object is destroyed on exiting the block.
00339     struct adjustor_base
00340     {
00341     private:
00342       const double _M_orig;
00343 
00344     public:
00345       adjustor_base() : _M_orig(probability()) { }
00346 
00347       virtual ~adjustor_base()
00348       { set_probability(_M_orig); }
00349     };
00350 
00351     /// Group condition.
00352     struct group_adjustor : public adjustor_base
00353     {
00354       group_adjustor(size_t size)
00355       { set_probability(1 - std::pow(double(1 - probability()),
00356                      double(0.5 / (size + 1))));
00357       }
00358     };
00359 
00360     /// Never enter the condition.
00361     struct never_adjustor : public adjustor_base
00362     {
00363       never_adjustor() { set_probability(0); }
00364     };
00365 
00366     /// Always enter the condition.
00367     struct always_adjustor : public adjustor_base
00368     {
00369       always_adjustor() { set_probability(1); }
00370     };
00371 
00372     random_condition()
00373     {
00374       probability();
00375       engine();
00376     }
00377 
00378     static void
00379     set_probability(double __p)
00380     { probability() = __p; }
00381 
00382     static void
00383     throw_conditionally()
00384     {
00385       if (generate() < probability())
00386     __throw_forced_error();
00387     }
00388 
00389     void
00390     seed(unsigned long __s)
00391     { engine().seed(__s); }
00392 
00393   private:
00394 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00395     typedef std::uniform_real_distribution<double>  distribution_type;
00396     typedef std::mt19937                engine_type;
00397 #else
00398     typedef std::tr1::uniform_real<double>      distribution_type;
00399     typedef std::tr1::mt19937               engine_type;
00400 #endif
00401 
00402     static double
00403     generate()
00404     {
00405 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00406       const distribution_type distribution(0, 1);
00407       static auto generator = std::bind(distribution, engine());
00408 #else
00409       // Use variate_generator to get normalized results.
00410       typedef std::tr1::variate_generator<engine_type, distribution_type> gen_t;
00411       distribution_type distribution(0, 1);
00412       static gen_t generator(engine(), distribution);
00413 #endif
00414 
00415       double random = generator();
00416       if (random < distribution.min() || random > distribution.max())
00417     {
00418       std::string __s("random_condition::generate");
00419       __s += "\n";
00420       __s += "random number generated is: ";
00421       char buf[40];
00422       __builtin_sprintf(buf, "%f", random);
00423       __s += buf;
00424       std::__throw_out_of_range(__s.c_str());
00425     }
00426 
00427       return random;
00428     }
00429 
00430     static double&
00431     probability()
00432     {
00433       static double _S_p;
00434       return _S_p;
00435     }
00436 
00437     static engine_type&
00438     engine()
00439     {
00440       static engine_type _S_e;
00441       return _S_e;
00442     }
00443   };
00444 
00445 
00446   /**
00447    *  @brief Class with exception generation control. Intended to be
00448    *  used as a value_type in templatized code.
00449    *
00450    *  Note: Destructor not allowed to throw.
00451    */
00452   template<typename _Cond>
00453     struct throw_value_base : public _Cond
00454     {
00455       typedef _Cond                 condition_type;
00456 
00457       using condition_type::throw_conditionally;
00458 
00459       std::size_t                   _M_i;
00460 
00461 #ifndef _GLIBCXX_IS_AGGREGATE
00462       throw_value_base() : _M_i(0)
00463       { throw_conditionally(); }
00464 
00465       throw_value_base(const throw_value_base& __v) : _M_i(__v._M_i)
00466       { throw_conditionally(); }
00467 
00468       explicit throw_value_base(const std::size_t __i) : _M_i(__i)
00469       { throw_conditionally(); }
00470 #endif
00471 
00472       throw_value_base&
00473       operator=(const throw_value_base& __v)
00474       {
00475     throw_conditionally();
00476     _M_i = __v._M_i;
00477     return *this;
00478       }
00479 
00480       throw_value_base&
00481       operator++()
00482       {
00483     throw_conditionally();
00484     ++_M_i;
00485     return *this;
00486       }
00487     };
00488 
00489   template<typename _Cond>
00490     inline void
00491     swap(throw_value_base<_Cond>& __a, throw_value_base<_Cond>& __b)
00492     {
00493       typedef throw_value_base<_Cond> throw_value;
00494       throw_value::throw_conditionally();
00495       throw_value orig(__a);
00496       __a = __b;
00497       __b = orig;
00498     }
00499 
00500   // General instantiable types requirements.
00501   template<typename _Cond>
00502     inline bool
00503     operator==(const throw_value_base<_Cond>& __a,
00504            const throw_value_base<_Cond>& __b)
00505     {
00506       typedef throw_value_base<_Cond> throw_value;
00507       throw_value::throw_conditionally();
00508       bool __ret = __a._M_i == __b._M_i;
00509       return __ret;
00510     }
00511 
00512   template<typename _Cond>
00513     inline bool
00514     operator<(const throw_value_base<_Cond>& __a,
00515           const throw_value_base<_Cond>& __b)
00516     {
00517       typedef throw_value_base<_Cond> throw_value;
00518       throw_value::throw_conditionally();
00519       bool __ret = __a._M_i < __b._M_i;
00520       return __ret;
00521     }
00522 
00523   // Numeric algorithms instantiable types requirements.
00524   template<typename _Cond>
00525     inline throw_value_base<_Cond>
00526     operator+(const throw_value_base<_Cond>& __a,
00527           const throw_value_base<_Cond>& __b)
00528     {
00529       typedef throw_value_base<_Cond> throw_value;
00530       throw_value::throw_conditionally();
00531       throw_value __ret(__a._M_i + __b._M_i);
00532       return __ret;
00533     }
00534 
00535   template<typename _Cond>
00536     inline throw_value_base<_Cond>
00537     operator-(const throw_value_base<_Cond>& __a,
00538           const throw_value_base<_Cond>& __b)
00539     {
00540       typedef throw_value_base<_Cond> throw_value;
00541       throw_value::throw_conditionally();
00542       throw_value __ret(__a._M_i - __b._M_i);
00543       return __ret;
00544     }
00545 
00546   template<typename _Cond>
00547     inline throw_value_base<_Cond>
00548     operator*(const throw_value_base<_Cond>& __a,
00549           const throw_value_base<_Cond>& __b)
00550     {
00551       typedef throw_value_base<_Cond> throw_value;
00552       throw_value::throw_conditionally();
00553       throw_value __ret(__a._M_i * __b._M_i);
00554       return __ret;
00555     }
00556 
00557 
00558   /// Type throwing via limit condition.
00559   struct throw_value_limit : public throw_value_base<limit_condition>
00560   {
00561     typedef throw_value_base<limit_condition> base_type;
00562 
00563 #ifndef _GLIBCXX_IS_AGGREGATE
00564     throw_value_limit() { }
00565 
00566     throw_value_limit(const throw_value_limit& __other)
00567     : base_type(__other._M_i) { }
00568 
00569     explicit throw_value_limit(const std::size_t __i) : base_type(__i) { }
00570 #endif
00571   };
00572 
00573   /// Type throwing via random condition.
00574   struct throw_value_random : public throw_value_base<random_condition>
00575   {
00576     typedef throw_value_base<random_condition> base_type;
00577 
00578 #ifndef _GLIBCXX_IS_AGGREGATE
00579     throw_value_random() { }
00580 
00581     throw_value_random(const throw_value_random& __other)
00582     : base_type(__other._M_i) { }
00583 
00584 
00585     explicit throw_value_random(const std::size_t __i) : base_type(__i) { }
00586 #endif
00587   };
00588 
00589 
00590   /**
00591    *  @brief Allocator class with logging and exception generation control.
00592    * Intended to be used as an allocator_type in templatized code.
00593    *  @ingroup allocators
00594    *
00595    *  Note: Deallocate not allowed to throw.
00596    */
00597   template<typename _Tp, typename _Cond>
00598     class throw_allocator_base
00599     : public annotate_base, public _Cond
00600     {
00601     public:
00602       typedef size_t                size_type;
00603       typedef ptrdiff_t             difference_type;
00604       typedef _Tp               value_type;
00605       typedef value_type*           pointer;
00606       typedef const value_type*         const_pointer;
00607       typedef value_type&           reference;
00608       typedef const value_type&         const_reference;
00609 
00610     private:
00611       typedef _Cond             condition_type;
00612 
00613       std::allocator<value_type>        _M_allocator;
00614 
00615       using condition_type::throw_conditionally;
00616 
00617     public:
00618       size_type
00619       max_size() const throw()
00620       { return _M_allocator.max_size(); }
00621 
00622       pointer
00623       allocate(size_type __n, std::allocator<void>::const_pointer hint = 0)
00624       {
00625     if (__n > this->max_size())
00626       std::__throw_bad_alloc();
00627 
00628     throw_conditionally();
00629     pointer const a = _M_allocator.allocate(__n, hint);
00630     insert(a, sizeof(value_type) * __n);
00631     return a;
00632       }
00633 
00634       void
00635       construct(pointer __p, const value_type& val)
00636       { return _M_allocator.construct(__p, val); }
00637 
00638 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00639       template<typename... _Args>
00640     void
00641     construct(pointer __p, _Args&&... __args)
00642     { return _M_allocator.construct(__p, std::forward<_Args>(__args)...); }
00643 #endif
00644 
00645       void
00646       destroy(pointer __p)
00647       { _M_allocator.destroy(__p); }
00648 
00649       void
00650       deallocate(pointer __p, size_type __n)
00651       {
00652     erase(__p, sizeof(value_type) * __n);
00653     _M_allocator.deallocate(__p, __n);
00654       }
00655 
00656       void
00657       check_allocated(pointer __p, size_type __n)
00658       {
00659     size_type __t = sizeof(value_type) * __n;
00660     annotate_base::check_allocated(__p, __t);
00661       }
00662 
00663       void
00664       check_allocated(size_type __n)
00665       { annotate_base::check_allocated(__n); }
00666   };
00667 
00668   template<typename _Tp, typename _Cond>
00669     inline bool
00670     operator==(const throw_allocator_base<_Tp, _Cond>&,
00671            const throw_allocator_base<_Tp, _Cond>&)
00672     { return true; }
00673 
00674   template<typename _Tp, typename _Cond>
00675     inline bool
00676     operator!=(const throw_allocator_base<_Tp, _Cond>&,
00677            const throw_allocator_base<_Tp, _Cond>&)
00678     { return false; }
00679 
00680   /// Allocator throwing via limit condition.
00681   template<typename _Tp>
00682     struct throw_allocator_limit
00683     : public throw_allocator_base<_Tp, limit_condition>
00684     {
00685       template<typename _Tp1>
00686     struct rebind
00687     { typedef throw_allocator_limit<_Tp1> other; };
00688 
00689       throw_allocator_limit() throw() { }
00690 
00691       throw_allocator_limit(const throw_allocator_limit&) throw() { }
00692 
00693       template<typename _Tp1>
00694     throw_allocator_limit(const throw_allocator_limit<_Tp1>&) throw() { }
00695 
00696       ~throw_allocator_limit() throw() { }
00697     };
00698 
00699   /// Allocator throwing via random condition.
00700   template<typename _Tp>
00701     struct throw_allocator_random
00702     : public throw_allocator_base<_Tp, random_condition>
00703     {
00704       template<typename _Tp1>
00705     struct rebind
00706     { typedef throw_allocator_random<_Tp1> other; };
00707 
00708       throw_allocator_random() throw() { }
00709 
00710       throw_allocator_random(const throw_allocator_random&) throw() { }
00711 
00712       template<typename _Tp1>
00713     throw_allocator_random(const throw_allocator_random<_Tp1>&) throw() { }
00714 
00715       ~throw_allocator_random() throw() { }
00716     };
00717 
00718 _GLIBCXX_END_NAMESPACE
00719 
00720 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00721 
00722 # include <bits/functional_hash.h>
00723 
00724 namespace std
00725 {
00726   /// Explicit specialization of std::hash for __gnu_cxx::throw_value_limit.
00727   template<>
00728     struct hash<__gnu_cxx::throw_value_limit>
00729     : public std::unary_function<__gnu_cxx::throw_value_limit, size_t>
00730     {
00731       size_t
00732       operator()(const __gnu_cxx::throw_value_limit& __val) const
00733       {
00734     std::hash<std::size_t> h;
00735     size_t __result = h(__val._M_i);
00736     return __result;
00737       }
00738     };
00739 
00740   /// Explicit specialization of std::hash for __gnu_cxx::throw_value_limit.
00741   template<>
00742     struct hash<__gnu_cxx::throw_value_random>
00743     : public std::unary_function<__gnu_cxx::throw_value_random, size_t>
00744     {
00745       size_t
00746       operator()(const __gnu_cxx::throw_value_random& __val) const
00747       {
00748     std::hash<std::size_t> h;
00749     size_t __result = h(__val._M_i);
00750     return __result;
00751       }
00752     };
00753 } // end namespace std
00754 #endif
00755 
00756 #endif