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