]>
Commit | Line | Data |
---|---|---|
a86151e1 BK |
1 | // -*- C++ -*- |
2 | ||
5b9daa7e | 3 | // Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. |
a86151e1 BK |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the terms | |
7 | // of the GNU General Public License as published by the Free Software | |
748086b7 | 8 | // Foundation; either version 3, or (at your option) any later |
a86151e1 BK |
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 | ||
748086b7 JJ |
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. | |
a86151e1 | 19 | |
748086b7 JJ |
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/>. | |
a86151e1 BK |
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 | ||
65be6ddd | 36 | /** @file ext/throw_allocator.h |
78a53887 BK |
37 | * This file is a GNU extension to the Standard C++ Library. |
38 | * | |
39 | * Contains an exception-throwing allocator, useful for testing | |
40 | * exception safety. In addition, allocation addresses are stored and | |
41 | * sanity checked. | |
42 | */ | |
43 | ||
a86151e1 BK |
44 | #ifndef _THROW_ALLOCATOR_H |
45 | #define _THROW_ALLOCATOR_H 1 | |
46 | ||
47 | #include <cmath> | |
67a7356b | 48 | #include <ctime> |
a86151e1 | 49 | #include <map> |
a86151e1 BK |
50 | #include <string> |
51 | #include <ostream> | |
52 | #include <stdexcept> | |
53 | #include <utility> | |
949d9ae1 | 54 | #include <bits/functexcept.h> |
ca0f8fd1 | 55 | #include <bits/move.h> |
5580c6e7 BK |
56 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
57 | # include <functional> | |
58 | # include <random> | |
59 | #else | |
60 | # include <tr1/functional> | |
61 | # include <tr1/random> | |
62 | #endif | |
a86151e1 BK |
63 | |
64 | _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) | |
65 | ||
5580c6e7 | 66 | /** |
5b9daa7e BK |
67 | * @brief Thown by throw_allocator. |
68 | * @ingroup exceptions | |
69 | */ | |
a86151e1 BK |
70 | struct forced_exception_error : public std::exception |
71 | { }; | |
72 | ||
949d9ae1 BK |
73 | // Substitute for concurrence_error object in the case of -fno-exceptions. |
74 | inline void | |
75 | __throw_forced_exception_error() | |
76 | { | |
77 | #if __EXCEPTIONS | |
78 | throw forced_exception_error(); | |
79 | #else | |
80 | __builtin_abort(); | |
81 | #endif | |
82 | } | |
83 | ||
5580c6e7 BK |
84 | // Base class for checking address and label information about |
85 | // allocations. Create a std::map between the allocated address | |
86 | // (void*) and a datum for annotations, which are a pair of numbers | |
87 | // corresponding to label and allocated size. | |
88 | struct annotate_base | |
a86151e1 | 89 | { |
5580c6e7 BK |
90 | annotate_base() |
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 | ||
a86151e1 | 104 | void |
5580c6e7 BK |
105 | insert(void* p, size_t size) |
106 | { | |
107 | if (p == NULL) | |
108 | { | |
109 | std::string error("throw_allocator_base::insert null insert!\n"); | |
110 | log_to_string(error, make_entry(p, size)); | |
111 | std::__throw_logic_error(error.c_str()); | |
112 | } | |
a86151e1 | 113 | |
5580c6e7 BK |
114 | const_iterator found = map().find(p); |
115 | if (found != map().end()) | |
116 | { | |
117 | std::string error("throw_allocator_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 | } | |
a86151e1 | 122 | |
5580c6e7 BK |
123 | map().insert(make_entry(p, size)); |
124 | } | |
a86151e1 | 125 | |
5580c6e7 BK |
126 | void |
127 | erase(void* p, size_t size) | |
128 | { | |
129 | check_allocated(p, size); | |
130 | map().erase(p); | |
131 | } | |
a86151e1 | 132 | |
5580c6e7 BK |
133 | // See if a particular address and size has been allocated. |
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 | } | |
a86151e1 | 155 | |
5580c6e7 BK |
156 | // See if a given label has been allocated. |
157 | inline void | |
158 | check_allocated(size_t label) | |
a86151e1 | 159 | { |
5580c6e7 BK |
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: | |
179 | typedef std::pair<size_t, size_t> data_type; | |
180 | typedef std::map<void*, data_type> map_type; | |
181 | typedef map_type::value_type entry_type; | |
182 | typedef map_type::const_iterator const_iterator; | |
183 | typedef map_type::const_reference const_reference; | |
a86151e1 | 184 | |
5580c6e7 BK |
185 | friend std::ostream& |
186 | operator<<(std::ostream&, const annotate_base&); | |
a86151e1 | 187 | |
5580c6e7 BK |
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 ll; | |
217 | return ll; | |
218 | } | |
219 | ||
220 | static map_type& | |
221 | map() | |
222 | { | |
223 | static map_type mp; | |
224 | return mp; | |
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 | /// Base class for probability control and throw. | |
241 | struct probability_base | |
242 | { | |
243 | // Scope-level probability adjustor objects: set probability for | |
244 | // throw at the beginning of a scope block, and restores to | |
245 | // previous probability when object is destroyed on exiting the | |
246 | // block. | |
247 | struct adjustor_base | |
248 | { | |
a86151e1 | 249 | private: |
5580c6e7 BK |
250 | const double _M_prob; |
251 | ||
252 | public: | |
253 | adjustor_base() : _M_prob(get_probability()) { } | |
254 | ||
255 | virtual ~adjustor_base() | |
256 | { set_probability(_M_prob); } | |
a86151e1 BK |
257 | }; |
258 | ||
5580c6e7 BK |
259 | // Group condition. |
260 | struct group_adjustor : public adjustor_base | |
a86151e1 | 261 | { |
5580c6e7 BK |
262 | group_adjustor(size_t size) |
263 | { set_probability(1 - std::pow(double(1 - get_probability()), | |
264 | double(0.5 / (size + 1)))); | |
265 | } | |
266 | }; | |
a86151e1 | 267 | |
5580c6e7 BK |
268 | // Never enter the condition. |
269 | struct never_adjustor : public adjustor_base | |
270 | { | |
271 | never_adjustor() { set_probability(0); } | |
272 | }; | |
a86151e1 | 273 | |
5580c6e7 BK |
274 | // Always enter the condition. |
275 | struct always_adjustor : public adjustor_base | |
276 | { | |
277 | always_adjustor() { set_probability(1); } | |
a86151e1 BK |
278 | }; |
279 | ||
5580c6e7 BK |
280 | probability_base() |
281 | { | |
282 | probability(); | |
283 | engine(); | |
284 | } | |
a86151e1 BK |
285 | |
286 | static void | |
5580c6e7 BK |
287 | set_probability(double __p) |
288 | { probability() = __p; } | |
a86151e1 | 289 | |
5580c6e7 BK |
290 | static double& |
291 | get_probability() | |
292 | { return probability(); } | |
a86151e1 | 293 | |
5580c6e7 BK |
294 | void |
295 | throw_conditionally() | |
296 | { | |
297 | if (generate() < get_probability()) | |
298 | __throw_forced_exception_error(); | |
299 | } | |
a86151e1 | 300 | |
5580c6e7 BK |
301 | void |
302 | seed(unsigned long __s) | |
303 | { engine().seed(__s); } | |
a86151e1 BK |
304 | |
305 | private: | |
5580c6e7 BK |
306 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
307 | typedef std::uniform_real_distribution<double> distribution_type; | |
308 | typedef std::mt19937 engine_type; | |
309 | #else | |
310 | typedef std::tr1::uniform_real<double> distribution_type; | |
311 | typedef std::tr1::mt19937 engine_type; | |
312 | #endif | |
a86151e1 | 313 | |
5580c6e7 BK |
314 | double |
315 | generate() | |
316 | { | |
317 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ | |
318 | const distribution_type distribution(0, 1); | |
319 | static auto generator = std::bind(distribution, engine()); | |
320 | #else | |
321 | // Use variate_generator to get normalized results. | |
322 | typedef std::tr1::variate_generator<engine_type, distribution_type> gen_t; | |
323 | distribution_type distribution(0, 1); | |
324 | static gen_t generator(engine(), distribution); | |
325 | #endif | |
a86151e1 | 326 | |
5580c6e7 BK |
327 | double random = generator(); |
328 | if (random < distribution.min() || random > distribution.max()) | |
329 | { | |
330 | std::string __s("throw_allocator::throw_conditionally"); | |
331 | __s += "\n"; | |
332 | __s += "random number generated is: "; | |
333 | char buf[40]; | |
334 | __builtin_sprintf(buf, "%f", random); | |
335 | __s += buf; | |
336 | std::__throw_out_of_range(__s.c_str()); | |
337 | } | |
a86151e1 | 338 | |
5580c6e7 BK |
339 | return random; |
340 | } | |
a86151e1 | 341 | |
5580c6e7 BK |
342 | static double& |
343 | probability() | |
344 | { | |
345 | static double __p; | |
346 | return __p; | |
347 | } | |
a86151e1 | 348 | |
5580c6e7 BK |
349 | static engine_type& |
350 | engine() | |
351 | { | |
352 | static engine_type __e; | |
353 | return __e; | |
354 | } | |
a86151e1 BK |
355 | }; |
356 | ||
5580c6e7 | 357 | /** |
5b9daa7e BK |
358 | * @brief Allocator class with logging and exception control. |
359 | * @ingroup allocators | |
360 | */ | |
a86151e1 | 361 | template<typename T> |
5580c6e7 BK |
362 | class throw_allocator |
363 | : public probability_base, public annotate_base | |
a86151e1 BK |
364 | { |
365 | public: | |
3441f106 BK |
366 | typedef size_t size_type; |
367 | typedef ptrdiff_t difference_type; | |
368 | typedef T value_type; | |
369 | typedef value_type* pointer; | |
370 | typedef const value_type* const_pointer; | |
371 | typedef value_type& reference; | |
372 | typedef const value_type& const_reference; | |
373 | ||
5580c6e7 BK |
374 | private: |
375 | std::allocator<value_type> _M_allocator; | |
a86151e1 | 376 | |
5580c6e7 | 377 | public: |
a86151e1 BK |
378 | template<typename U> |
379 | struct rebind | |
380 | { | |
5580c6e7 | 381 | typedef throw_allocator<U> other; |
a86151e1 BK |
382 | }; |
383 | ||
384 | throw_allocator() throw() { } | |
385 | ||
3441f106 | 386 | throw_allocator(const throw_allocator&) throw() { } |
a86151e1 | 387 | |
3441f106 | 388 | template<typename U> |
5580c6e7 | 389 | throw_allocator(const throw_allocator<U>&) throw() { } |
a86151e1 BK |
390 | |
391 | ~throw_allocator() throw() { } | |
392 | ||
393 | size_type | |
394 | max_size() const throw() | |
5580c6e7 | 395 | { return _M_allocator.max_size(); } |
a86151e1 BK |
396 | |
397 | pointer | |
b8637750 | 398 | allocate(size_type __n, std::allocator<void>::const_pointer hint = 0) |
a86151e1 | 399 | { |
e762c6f4 | 400 | if (__n > this->max_size()) |
b8637750 BK |
401 | std::__throw_bad_alloc(); |
402 | ||
a86151e1 | 403 | throw_conditionally(); |
5580c6e7 | 404 | pointer const a = _M_allocator.allocate(__n, hint); |
b8637750 | 405 | insert(a, sizeof(value_type) * __n); |
a86151e1 BK |
406 | return a; |
407 | } | |
408 | ||
409 | void | |
b8637750 | 410 | construct(pointer __p, const T& val) |
5580c6e7 | 411 | { return _M_allocator.construct(__p, val); } |
a86151e1 | 412 | |
61fcb9fb PC |
413 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
414 | template<typename... _Args> | |
5580c6e7 BK |
415 | void |
416 | construct(pointer __p, _Args&&... __args) | |
417 | { return _M_allocator.construct(__p, std::forward<_Args>(__args)...); } | |
61fcb9fb PC |
418 | #endif |
419 | ||
a86151e1 | 420 | void |
b8637750 | 421 | destroy(pointer __p) |
5580c6e7 | 422 | { _M_allocator.destroy(__p); } |
a86151e1 BK |
423 | |
424 | void | |
b8637750 | 425 | deallocate(pointer __p, size_type __n) |
a86151e1 | 426 | { |
b8637750 | 427 | erase(__p, sizeof(value_type) * __n); |
5580c6e7 | 428 | _M_allocator.deallocate(__p, __n); |
a86151e1 BK |
429 | } |
430 | ||
431 | void | |
b8637750 | 432 | check_allocated(pointer __p, size_type __n) |
5580c6e7 BK |
433 | { |
434 | size_type __t = sizeof(value_type) * __n; | |
435 | annotate_base::check_allocated(__p, __t); | |
436 | } | |
3441f106 | 437 | |
5580c6e7 | 438 | using annotate_base::check_allocated; |
a86151e1 BK |
439 | }; |
440 | ||
441 | template<typename T> | |
442 | inline bool | |
443 | operator==(const throw_allocator<T>&, const throw_allocator<T>&) | |
444 | { return true; } | |
445 | ||
446 | template<typename T> | |
447 | inline bool | |
448 | operator!=(const throw_allocator<T>&, const throw_allocator<T>&) | |
449 | { return false; } | |
450 | ||
a86151e1 BK |
451 | _GLIBCXX_END_NAMESPACE |
452 | ||
5580c6e7 | 453 | #endif |