]>
Commit | Line | Data |
---|---|---|
285b36d6 BK |
1 | // Debugging mode support code -*- C++ -*- |
2 | ||
77e0bf4e FD |
3 | // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |
4 | // 2011 Free Software Foundation, Inc. | |
285b36d6 BK |
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 | |
8 | // terms of the GNU General Public License as published by the | |
748086b7 | 9 | // Free Software Foundation; either version 3, or (at your option) |
285b36d6 BK |
10 | // any later version. |
11 | ||
12 | // This library is distributed in the hope that it will be useful, | |
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | // GNU General Public License for more details. | |
16 | ||
748086b7 JJ |
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. | |
285b36d6 | 20 | |
748086b7 JJ |
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/>. | |
285b36d6 BK |
25 | |
26 | #include <debug/debug.h> | |
27 | #include <debug/safe_sequence.h> | |
364c862b | 28 | #include <debug/safe_unordered_container.h> |
285b36d6 | 29 | #include <debug/safe_iterator.h> |
77e0bf4e | 30 | #include <debug/safe_local_iterator.h> |
285b36d6 | 31 | #include <algorithm> |
285b36d6 BK |
32 | #include <cassert> |
33 | #include <cstring> | |
285b36d6 | 34 | #include <cctype> |
39b8cd70 | 35 | #include <cstdio> |
5dddb7e5 | 36 | #include <cstdlib> |
afe96d41 | 37 | #include <functional> |
285b36d6 BK |
38 | |
39 | using namespace std; | |
40 | ||
b82f782b | 41 | namespace |
656cee9a | 42 | { |
afe96d41 FD |
43 | /** Returns different instances of __mutex depending on the passed address |
44 | * in order to limit contention without breaking current library binary | |
45 | * compatibility. */ | |
99827523 | 46 | __gnu_cxx::__mutex& |
afe96d41 | 47 | get_safe_base_mutex(void* __address) |
99827523 | 48 | { |
afe96d41 FD |
49 | const size_t mask = 0xf; |
50 | static __gnu_cxx::__mutex safe_base_mutex[mask + 1]; | |
51 | const size_t index = _Hash_impl::hash(__address) & mask; | |
52 | return safe_base_mutex[index]; | |
53 | } | |
54 | ||
55 | void | |
77e0bf4e FD |
56 | swap_its(__gnu_debug::_Safe_sequence_base& __lhs, |
57 | __gnu_debug::_Safe_iterator_base*& __lhs_its, | |
58 | __gnu_debug::_Safe_sequence_base& __rhs, | |
59 | __gnu_debug::_Safe_iterator_base*& __rhs_its) | |
afe96d41 | 60 | { |
77e0bf4e | 61 | swap(__lhs_its, __rhs_its); |
afe96d41 | 62 | __gnu_debug::_Safe_iterator_base* __iter; |
77e0bf4e | 63 | for (__iter = __rhs_its; __iter; __iter = __iter->_M_next) |
afe96d41 | 64 | __iter->_M_sequence = &__rhs; |
77e0bf4e | 65 | for (__iter = __lhs_its; __iter; __iter = __iter->_M_next) |
afe96d41 | 66 | __iter->_M_sequence = &__lhs; |
99827523 | 67 | } |
77e0bf4e FD |
68 | |
69 | void | |
70 | swap_seq(__gnu_debug::_Safe_sequence_base& __lhs, | |
71 | __gnu_debug::_Safe_sequence_base& __rhs) | |
72 | { | |
73 | swap(__lhs._M_version, __rhs._M_version); | |
74 | swap_its(__lhs, __lhs._M_iterators, | |
75 | __rhs, __rhs._M_iterators); | |
76 | swap_its(__lhs, __lhs._M_const_iterators, | |
77 | __rhs, __rhs._M_const_iterators); | |
78 | } | |
79 | ||
80 | void | |
364c862b FD |
81 | swap_ucont(__gnu_debug::_Safe_unordered_container_base& __lhs, |
82 | __gnu_debug::_Safe_unordered_container_base& __rhs) | |
77e0bf4e FD |
83 | { |
84 | swap_seq(__lhs, __rhs); | |
85 | swap_its(__lhs, __lhs._M_local_iterators, | |
86 | __rhs, __rhs._M_local_iterators); | |
87 | swap_its(__lhs, __lhs._M_const_local_iterators, | |
88 | __rhs, __rhs._M_const_local_iterators); | |
89 | } | |
90 | ||
91 | void | |
92 | detach_all(__gnu_debug::_Safe_iterator_base* __iter) | |
93 | { | |
94 | for (; __iter;) | |
95 | { | |
96 | __gnu_debug::_Safe_iterator_base* __old = __iter; | |
97 | __iter = __iter->_M_next; | |
98 | __old->_M_reset(); | |
99 | } | |
100 | } | |
2e362c74 | 101 | } // anonymous namespace |
656cee9a | 102 | |
285b36d6 BK |
103 | namespace __gnu_debug |
104 | { | |
105 | const char* _S_debug_messages[] = | |
106 | { | |
77e0bf4e | 107 | // General Checks |
285b36d6 BK |
108 | "function requires a valid iterator range [%1.name;, %2.name;)", |
109 | "attempt to insert into container with a singular iterator", | |
4be58168 BK |
110 | "attempt to insert into container with an iterator" |
111 | " from a different container", | |
285b36d6 | 112 | "attempt to erase from container with a %2.state; iterator", |
4be58168 BK |
113 | "attempt to erase from container with an iterator" |
114 | " from a different container", | |
115 | "attempt to subscript container with out-of-bounds index %2;," | |
116 | " but container only holds %3; elements", | |
285b36d6 | 117 | "attempt to access an element in an empty container", |
4be58168 BK |
118 | "elements in iterator range [%1.name;, %2.name;)" |
119 | " are not partitioned by the value %3;", | |
120 | "elements in iterator range [%1.name;, %2.name;)" | |
121 | " are not partitioned by the predicate %3; and value %4;", | |
285b36d6 | 122 | "elements in iterator range [%1.name;, %2.name;) are not sorted", |
4be58168 BK |
123 | "elements in iterator range [%1.name;, %2.name;)" |
124 | " are not sorted according to the predicate %3;", | |
285b36d6 | 125 | "elements in iterator range [%1.name;, %2.name;) do not form a heap", |
4be58168 BK |
126 | "elements in iterator range [%1.name;, %2.name;)" |
127 | " do not form a heap with respect to the predicate %3;", | |
77e0bf4e | 128 | // std::bitset checks |
285b36d6 BK |
129 | "attempt to write through a singular bitset reference", |
130 | "attempt to read from a singular bitset reference", | |
131 | "attempt to flip a singular bitset reference", | |
77e0bf4e | 132 | // std::list checks |
285b36d6 BK |
133 | "attempt to splice a list into itself", |
134 | "attempt to splice lists with inequal allocators", | |
135 | "attempt to splice elements referenced by a %1.state; iterator", | |
136 | "attempt to splice an iterator from a different container", | |
4be58168 BK |
137 | "splice destination %1.name;" |
138 | " occurs within source range [%2.name;, %3.name;)", | |
77e0bf4e | 139 | // iterator checks |
285b36d6 BK |
140 | "attempt to initialize an iterator that will immediately become singular", |
141 | "attempt to copy-construct an iterator from a singular iterator", | |
4be58168 BK |
142 | "attempt to construct a constant iterator" |
143 | " from a singular mutable iterator", | |
285b36d6 BK |
144 | "attempt to copy from a singular iterator", |
145 | "attempt to dereference a %1.state; iterator", | |
146 | "attempt to increment a %1.state; iterator", | |
147 | "attempt to decrement a %1.state; iterator", | |
4be58168 BK |
148 | "attempt to subscript a %1.state; iterator %2; step from" |
149 | " its current position, which falls outside its dereferenceable range", | |
150 | "attempt to advance a %1.state; iterator %2; steps," | |
151 | " which falls outside its valid range", | |
152 | "attempt to retreat a %1.state; iterator %2; steps," | |
153 | " which falls outside its valid range", | |
285b36d6 BK |
154 | "attempt to compare a %1.state; iterator to a %2.state; iterator", |
155 | "attempt to compare iterators from different sequences", | |
156 | "attempt to order a %1.state; iterator to a %2.state; iterator", | |
157 | "attempt to order iterators from different sequences", | |
4be58168 BK |
158 | "attempt to compute the difference between a %1.state;" |
159 | " iterator to a %2.state; iterator", | |
160 | "attempt to compute the different between two iterators" | |
161 | " from different sequences", | |
77e0bf4e | 162 | // istream_iterator |
285b36d6 BK |
163 | "attempt to dereference an end-of-stream istream_iterator", |
164 | "attempt to increment an end-of-stream istream_iterator", | |
77e0bf4e | 165 | // ostream_iterator |
285b36d6 | 166 | "attempt to output via an ostream_iterator with no associated stream", |
77e0bf4e | 167 | // istreambuf_iterator |
4be58168 BK |
168 | "attempt to dereference an end-of-stream istreambuf_iterator" |
169 | " (this is a GNU extension)", | |
b8b4301e | 170 | "attempt to increment an end-of-stream istreambuf_iterator", |
77e0bf4e | 171 | // std::forward_list |
b8b4301e PC |
172 | "attempt to insert into container after an end iterator", |
173 | "attempt to erase from container after a %2.state; iterator not followed" | |
174 | " by a dereferenceable one", | |
68478bb4 | 175 | "function requires a valid iterator range (%2.name;, %3.name;)" |
77e0bf4e | 176 | ", \"%2.name;\" shall be before and not equal to \"%3.name;\"", |
364c862b FD |
177 | // std::unordered_container::local_iterator |
178 | "attempt to compare local iterators from different unordered container" | |
a8028a3e JW |
179 | " buckets", |
180 | "function requires a non-empty iterator range [%1.name;, %2.name;)" | |
285b36d6 BK |
181 | }; |
182 | ||
eebbe2c7 | 183 | void |
285b36d6 BK |
184 | _Safe_sequence_base:: |
185 | _M_detach_all() | |
186 | { | |
99827523 | 187 | __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); |
77e0bf4e | 188 | detach_all(_M_iterators); |
afe96d41 | 189 | _M_iterators = 0; |
285b36d6 | 190 | |
77e0bf4e | 191 | detach_all(_M_const_iterators); |
afe96d41 | 192 | _M_const_iterators = 0; |
285b36d6 BK |
193 | } |
194 | ||
eebbe2c7 | 195 | void |
285b36d6 BK |
196 | _Safe_sequence_base:: |
197 | _M_detach_singular() | |
198 | { | |
99827523 | 199 | __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); |
eebbe2c7 | 200 | for (_Safe_iterator_base* __iter = _M_iterators; __iter;) |
4be58168 | 201 | { |
f18be892 PC |
202 | _Safe_iterator_base* __old = __iter; |
203 | __iter = __iter->_M_next; | |
204 | if (__old->_M_singular()) | |
eebbe2c7 | 205 | __old->_M_detach_single(); |
4be58168 | 206 | } |
285b36d6 | 207 | |
eebbe2c7 | 208 | for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2;) |
4be58168 | 209 | { |
95b147fe SM |
210 | _Safe_iterator_base* __old = __iter2; |
211 | __iter2 = __iter2->_M_next; | |
f18be892 | 212 | if (__old->_M_singular()) |
eebbe2c7 | 213 | __old->_M_detach_single(); |
4be58168 | 214 | } |
285b36d6 | 215 | } |
cd07aa11 PC |
216 | |
217 | void | |
285b36d6 BK |
218 | _Safe_sequence_base:: |
219 | _M_revalidate_singular() | |
220 | { | |
99827523 | 221 | __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); |
cd07aa11 PC |
222 | for (_Safe_iterator_base* __iter = _M_iterators; __iter; |
223 | __iter = __iter->_M_next) | |
224 | __iter->_M_version = _M_version; | |
225 | ||
226 | for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2; | |
227 | __iter2 = __iter2->_M_next) | |
228 | __iter2->_M_version = _M_version; | |
285b36d6 BK |
229 | } |
230 | ||
eebbe2c7 | 231 | void |
285b36d6 BK |
232 | _Safe_sequence_base:: |
233 | _M_swap(_Safe_sequence_base& __x) | |
234 | { | |
afe96d41 FD |
235 | // We need to lock both sequences to swap |
236 | using namespace __gnu_cxx; | |
237 | __mutex *__this_mutex = &_M_get_mutex(); | |
238 | __mutex *__x_mutex = &__x._M_get_mutex(); | |
239 | if (__this_mutex == __x_mutex) | |
240 | { | |
241 | __scoped_lock __lock(*__this_mutex); | |
242 | swap_seq(*this, __x); | |
243 | } | |
244 | else | |
245 | { | |
246 | __scoped_lock __l1(__this_mutex < __x_mutex | |
247 | ? *__this_mutex : *__x_mutex); | |
248 | __scoped_lock __l2(__this_mutex < __x_mutex | |
249 | ? *__x_mutex : *__this_mutex); | |
250 | swap_seq(*this, __x); | |
251 | } | |
285b36d6 | 252 | } |
eebbe2c7 PC |
253 | |
254 | __gnu_cxx::__mutex& | |
255 | _Safe_sequence_base:: | |
5d51b87a | 256 | _M_get_mutex() throw () |
afe96d41 FD |
257 | { return get_safe_base_mutex(this); } |
258 | ||
259 | void | |
260 | _Safe_sequence_base:: | |
261 | _M_attach(_Safe_iterator_base* __it, bool __constant) | |
262 | { | |
263 | __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); | |
264 | _M_attach_single(__it, __constant); | |
265 | } | |
266 | ||
267 | void | |
268 | _Safe_sequence_base:: | |
269 | _M_attach_single(_Safe_iterator_base* __it, bool __constant) throw () | |
270 | { | |
271 | _Safe_iterator_base*& __its = | |
272 | __constant ? _M_const_iterators : _M_iterators; | |
273 | __it->_M_next = __its; | |
274 | if (__it->_M_next) | |
275 | __it->_M_next->_M_prior = __it; | |
276 | __its = __it; | |
277 | } | |
278 | ||
279 | void | |
280 | _Safe_sequence_base:: | |
281 | _M_detach(_Safe_iterator_base* __it) | |
282 | { | |
283 | // Remove __it from this sequence's list | |
284 | __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); | |
285 | _M_detach_single(__it); | |
286 | } | |
287 | ||
288 | void | |
289 | _Safe_sequence_base:: | |
290 | _M_detach_single(_Safe_iterator_base* __it) throw () | |
291 | { | |
292 | // Remove __it from this sequence's list | |
8c9f4dfa | 293 | __it->_M_unlink(); |
afe96d41 FD |
294 | if (_M_const_iterators == __it) |
295 | _M_const_iterators = __it->_M_next; | |
296 | if (_M_iterators == __it) | |
297 | _M_iterators = __it->_M_next; | |
298 | } | |
eebbe2c7 PC |
299 | |
300 | void | |
285b36d6 BK |
301 | _Safe_iterator_base:: |
302 | _M_attach(_Safe_sequence_base* __seq, bool __constant) | |
303 | { | |
afe96d41 FD |
304 | _M_detach(); |
305 | ||
306 | // Attach to the new sequence (if there is one) | |
307 | if (__seq) | |
308 | { | |
309 | _M_sequence = __seq; | |
310 | _M_version = _M_sequence->_M_version; | |
311 | _M_sequence->_M_attach(this, __constant); | |
312 | } | |
eebbe2c7 PC |
313 | } |
314 | ||
315 | void | |
316 | _Safe_iterator_base:: | |
5d51b87a | 317 | _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw () |
eebbe2c7 PC |
318 | { |
319 | _M_detach_single(); | |
285b36d6 BK |
320 | |
321 | // Attach to the new sequence (if there is one) | |
322 | if (__seq) | |
285b36d6 | 323 | { |
4be58168 BK |
324 | _M_sequence = __seq; |
325 | _M_version = _M_sequence->_M_version; | |
afe96d41 | 326 | _M_sequence->_M_attach_single(this, __constant); |
285b36d6 | 327 | } |
285b36d6 BK |
328 | } |
329 | ||
eebbe2c7 | 330 | void |
285b36d6 BK |
331 | _Safe_iterator_base:: |
332 | _M_detach() | |
333 | { | |
afe96d41 | 334 | if (_M_sequence) |
77e0bf4e | 335 | _M_sequence->_M_detach(this); |
afe96d41 FD |
336 | |
337 | _M_reset(); | |
eebbe2c7 PC |
338 | } |
339 | ||
340 | void | |
341 | _Safe_iterator_base:: | |
5d51b87a | 342 | _M_detach_single() throw () |
eebbe2c7 | 343 | { |
285b36d6 | 344 | if (_M_sequence) |
77e0bf4e | 345 | _M_sequence->_M_detach_single(this); |
285b36d6 | 346 | |
afe96d41 FD |
347 | _M_reset(); |
348 | } | |
349 | ||
350 | void | |
351 | _Safe_iterator_base:: | |
352 | _M_reset() throw () | |
353 | { | |
285b36d6 BK |
354 | _M_sequence = 0; |
355 | _M_version = 0; | |
356 | _M_prior = 0; | |
357 | _M_next = 0; | |
358 | } | |
eebbe2c7 | 359 | |
285b36d6 BK |
360 | bool |
361 | _Safe_iterator_base:: | |
5d51b87a | 362 | _M_singular() const throw () |
285b36d6 BK |
363 | { return !_M_sequence || _M_version != _M_sequence->_M_version; } |
364 | ||
365 | bool | |
366 | _Safe_iterator_base:: | |
5d51b87a | 367 | _M_can_compare(const _Safe_iterator_base& __x) const throw () |
285b36d6 | 368 | { |
3cbc7af0 BK |
369 | return (!_M_singular() |
370 | && !__x._M_singular() && _M_sequence == __x._M_sequence); | |
285b36d6 BK |
371 | } |
372 | ||
eebbe2c7 PC |
373 | __gnu_cxx::__mutex& |
374 | _Safe_iterator_base:: | |
5d51b87a | 375 | _M_get_mutex() throw () |
afe96d41 | 376 | { return get_safe_base_mutex(_M_sequence); } |
eebbe2c7 | 377 | |
364c862b | 378 | _Safe_unordered_container_base* |
77e0bf4e | 379 | _Safe_local_iterator_base:: |
364c862b FD |
380 | _M_get_container() const _GLIBCXX_NOEXCEPT |
381 | { return static_cast<_Safe_unordered_container_base*>(_M_sequence); } | |
77e0bf4e FD |
382 | |
383 | void | |
384 | _Safe_local_iterator_base:: | |
364c862b | 385 | _M_attach(_Safe_sequence_base* __cont, bool __constant) |
77e0bf4e FD |
386 | { |
387 | _M_detach(); | |
388 | ||
364c862b FD |
389 | // Attach to the new container (if there is one) |
390 | if (__cont) | |
77e0bf4e | 391 | { |
364c862b | 392 | _M_sequence = __cont; |
77e0bf4e | 393 | _M_version = _M_sequence->_M_version; |
364c862b | 394 | _M_get_container()->_M_attach_local(this, __constant); |
77e0bf4e FD |
395 | } |
396 | } | |
397 | ||
398 | void | |
399 | _Safe_local_iterator_base:: | |
364c862b | 400 | _M_attach_single(_Safe_sequence_base* __cont, bool __constant) throw () |
77e0bf4e FD |
401 | { |
402 | _M_detach_single(); | |
403 | ||
364c862b FD |
404 | // Attach to the new container (if there is one) |
405 | if (__cont) | |
77e0bf4e | 406 | { |
364c862b | 407 | _M_sequence = __cont; |
77e0bf4e | 408 | _M_version = _M_sequence->_M_version; |
364c862b | 409 | _M_get_container()->_M_attach_local_single(this, __constant); |
77e0bf4e FD |
410 | } |
411 | } | |
412 | ||
413 | void | |
414 | _Safe_local_iterator_base:: | |
415 | _M_detach() | |
416 | { | |
417 | if (_M_sequence) | |
364c862b | 418 | _M_get_container()->_M_detach_local(this); |
77e0bf4e FD |
419 | |
420 | _M_reset(); | |
421 | } | |
422 | ||
423 | void | |
424 | _Safe_local_iterator_base:: | |
425 | _M_detach_single() throw () | |
426 | { | |
427 | if (_M_sequence) | |
364c862b | 428 | _M_get_container()->_M_detach_local_single(this); |
77e0bf4e FD |
429 | |
430 | _M_reset(); | |
431 | } | |
432 | ||
433 | void | |
364c862b | 434 | _Safe_unordered_container_base:: |
77e0bf4e FD |
435 | _M_detach_all() |
436 | { | |
437 | __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); | |
438 | detach_all(_M_iterators); | |
439 | _M_iterators = 0; | |
440 | ||
441 | detach_all(_M_const_iterators); | |
442 | _M_const_iterators = 0; | |
443 | ||
444 | detach_all(_M_local_iterators); | |
445 | _M_local_iterators = 0; | |
446 | ||
447 | detach_all(_M_const_local_iterators); | |
448 | _M_const_local_iterators = 0; | |
449 | } | |
450 | ||
451 | void | |
364c862b FD |
452 | _Safe_unordered_container_base:: |
453 | _M_swap(_Safe_unordered_container_base& __x) | |
77e0bf4e | 454 | { |
364c862b | 455 | // We need to lock both containers to swap |
77e0bf4e FD |
456 | using namespace __gnu_cxx; |
457 | __mutex *__this_mutex = &_M_get_mutex(); | |
458 | __mutex *__x_mutex = &__x._M_get_mutex(); | |
459 | if (__this_mutex == __x_mutex) | |
460 | { | |
461 | __scoped_lock __lock(*__this_mutex); | |
364c862b | 462 | swap_ucont(*this, __x); |
77e0bf4e FD |
463 | } |
464 | else | |
465 | { | |
466 | __scoped_lock __l1(__this_mutex < __x_mutex | |
467 | ? *__this_mutex : *__x_mutex); | |
468 | __scoped_lock __l2(__this_mutex < __x_mutex | |
469 | ? *__x_mutex : *__this_mutex); | |
364c862b | 470 | swap_ucont(*this, __x); |
77e0bf4e FD |
471 | } |
472 | } | |
473 | ||
474 | void | |
364c862b | 475 | _Safe_unordered_container_base:: |
77e0bf4e FD |
476 | _M_attach_local(_Safe_iterator_base* __it, bool __constant) |
477 | { | |
478 | __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); | |
479 | _M_attach_local_single(__it, __constant); | |
480 | } | |
481 | ||
482 | void | |
364c862b | 483 | _Safe_unordered_container_base:: |
77e0bf4e FD |
484 | _M_attach_local_single(_Safe_iterator_base* __it, bool __constant) throw () |
485 | { | |
486 | _Safe_iterator_base*& __its = | |
487 | __constant ? _M_const_local_iterators : _M_local_iterators; | |
488 | __it->_M_next = __its; | |
489 | if (__it->_M_next) | |
490 | __it->_M_next->_M_prior = __it; | |
491 | __its = __it; | |
492 | } | |
493 | ||
494 | void | |
364c862b | 495 | _Safe_unordered_container_base:: |
77e0bf4e FD |
496 | _M_detach_local(_Safe_iterator_base* __it) |
497 | { | |
364c862b | 498 | // Remove __it from this container's list |
77e0bf4e FD |
499 | __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); |
500 | _M_detach_local_single(__it); | |
501 | } | |
502 | ||
503 | void | |
364c862b | 504 | _Safe_unordered_container_base:: |
77e0bf4e FD |
505 | _M_detach_local_single(_Safe_iterator_base* __it) throw () |
506 | { | |
364c862b | 507 | // Remove __it from this container's list |
77e0bf4e FD |
508 | __it->_M_unlink(); |
509 | if (_M_const_local_iterators == __it) | |
510 | _M_const_local_iterators = __it->_M_next; | |
511 | if (_M_local_iterators == __it) | |
512 | _M_local_iterators = __it->_M_next; | |
513 | } | |
514 | ||
285b36d6 BK |
515 | void |
516 | _Error_formatter::_Parameter:: | |
4be58168 | 517 | _M_print_field(const _Error_formatter* __formatter, const char* __name) const |
285b36d6 BK |
518 | { |
519 | assert(this->_M_kind != _Parameter::__unused_param); | |
f18be892 PC |
520 | const int __bufsize = 64; |
521 | char __buf[__bufsize]; | |
285b36d6 BK |
522 | |
523 | if (_M_kind == __iterator) | |
285b36d6 | 524 | { |
4be58168 BK |
525 | if (strcmp(__name, "name") == 0) |
526 | { | |
527 | assert(_M_variant._M_iterator._M_name); | |
528 | __formatter->_M_print_word(_M_variant._M_iterator._M_name); | |
529 | } | |
530 | else if (strcmp(__name, "address") == 0) | |
531 | { | |
f18be892 | 532 | __formatter->_M_format_word(__buf, __bufsize, "%p", |
4be58168 | 533 | _M_variant._M_iterator._M_address); |
f18be892 | 534 | __formatter->_M_print_word(__buf); |
4be58168 BK |
535 | } |
536 | else if (strcmp(__name, "type") == 0) | |
537 | { | |
0f136367 PC |
538 | if (!_M_variant._M_iterator._M_type) |
539 | __formatter->_M_print_word("<unknown type>"); | |
540 | else | |
541 | // TBD: demangle! | |
542 | __formatter->_M_print_word(_M_variant._M_iterator. | |
543 | _M_type->name()); | |
4be58168 BK |
544 | } |
545 | else if (strcmp(__name, "constness") == 0) | |
546 | { | |
547 | static const char* __constness_names[__last_constness] = | |
548 | { | |
549 | "<unknown>", | |
550 | "constant", | |
551 | "mutable" | |
552 | }; | |
0f136367 PC |
553 | __formatter->_M_print_word(__constness_names[_M_variant. |
554 | _M_iterator. | |
555 | _M_constness]); | |
4be58168 BK |
556 | } |
557 | else if (strcmp(__name, "state") == 0) | |
558 | { | |
559 | static const char* __state_names[__last_state] = | |
560 | { | |
561 | "<unknown>", | |
562 | "singular", | |
563 | "dereferenceable (start-of-sequence)", | |
564 | "dereferenceable", | |
b8b4301e | 565 | "past-the-end", |
68478bb4 | 566 | "before-begin" |
4be58168 | 567 | }; |
0f136367 PC |
568 | __formatter->_M_print_word(__state_names[_M_variant. |
569 | _M_iterator._M_state]); | |
4be58168 BK |
570 | } |
571 | else if (strcmp(__name, "sequence") == 0) | |
572 | { | |
573 | assert(_M_variant._M_iterator._M_sequence); | |
f18be892 | 574 | __formatter->_M_format_word(__buf, __bufsize, "%p", |
4be58168 | 575 | _M_variant._M_iterator._M_sequence); |
f18be892 | 576 | __formatter->_M_print_word(__buf); |
4be58168 BK |
577 | } |
578 | else if (strcmp(__name, "seq_type") == 0) | |
579 | { | |
0f136367 PC |
580 | if (!_M_variant._M_iterator._M_seq_type) |
581 | __formatter->_M_print_word("<unknown seq_type>"); | |
582 | else | |
583 | // TBD: demangle! | |
584 | __formatter->_M_print_word(_M_variant._M_iterator. | |
585 | _M_seq_type->name()); | |
4be58168 BK |
586 | } |
587 | else | |
588 | assert(false); | |
285b36d6 | 589 | } |
285b36d6 | 590 | else if (_M_kind == __sequence) |
285b36d6 | 591 | { |
4be58168 BK |
592 | if (strcmp(__name, "name") == 0) |
593 | { | |
594 | assert(_M_variant._M_sequence._M_name); | |
595 | __formatter->_M_print_word(_M_variant._M_sequence._M_name); | |
596 | } | |
597 | else if (strcmp(__name, "address") == 0) | |
598 | { | |
599 | assert(_M_variant._M_sequence._M_address); | |
f18be892 | 600 | __formatter->_M_format_word(__buf, __bufsize, "%p", |
4be58168 | 601 | _M_variant._M_sequence._M_address); |
f18be892 | 602 | __formatter->_M_print_word(__buf); |
4be58168 BK |
603 | } |
604 | else if (strcmp(__name, "type") == 0) | |
605 | { | |
0f136367 PC |
606 | if (!_M_variant._M_sequence._M_type) |
607 | __formatter->_M_print_word("<unknown type>"); | |
608 | else | |
609 | // TBD: demangle! | |
610 | __formatter->_M_print_word(_M_variant._M_sequence. | |
611 | _M_type->name()); | |
4be58168 BK |
612 | } |
613 | else | |
614 | assert(false); | |
285b36d6 | 615 | } |
285b36d6 | 616 | else if (_M_kind == __integer) |
285b36d6 | 617 | { |
4be58168 BK |
618 | if (strcmp(__name, "name") == 0) |
619 | { | |
620 | assert(_M_variant._M_integer._M_name); | |
621 | __formatter->_M_print_word(_M_variant._M_integer._M_name); | |
622 | } | |
623 | else | |
285b36d6 | 624 | assert(false); |
4be58168 | 625 | } |
285b36d6 | 626 | else if (_M_kind == __string) |
285b36d6 | 627 | { |
4be58168 BK |
628 | if (strcmp(__name, "name") == 0) |
629 | { | |
630 | assert(_M_variant._M_string._M_name); | |
631 | __formatter->_M_print_word(_M_variant._M_string._M_name); | |
632 | } | |
633 | else | |
634 | assert(false); | |
285b36d6 | 635 | } |
285b36d6 | 636 | else |
4be58168 BK |
637 | { |
638 | assert(false); | |
639 | } | |
285b36d6 | 640 | } |
4be58168 | 641 | |
285b36d6 BK |
642 | void |
643 | _Error_formatter::_Parameter:: | |
644 | _M_print_description(const _Error_formatter* __formatter) const | |
645 | { | |
f18be892 PC |
646 | const int __bufsize = 128; |
647 | char __buf[__bufsize]; | |
285b36d6 BK |
648 | |
649 | if (_M_kind == __iterator) | |
285b36d6 | 650 | { |
4be58168 BK |
651 | __formatter->_M_print_word("iterator "); |
652 | if (_M_variant._M_iterator._M_name) | |
653 | { | |
f18be892 | 654 | __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ", |
4be58168 | 655 | _M_variant._M_iterator._M_name); |
f18be892 | 656 | __formatter->_M_print_word(__buf); |
4be58168 BK |
657 | } |
658 | ||
f18be892 | 659 | __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n", |
4be58168 | 660 | _M_variant._M_iterator._M_address); |
f18be892 | 661 | __formatter->_M_print_word(__buf); |
4be58168 BK |
662 | if (_M_variant._M_iterator._M_type) |
663 | { | |
664 | __formatter->_M_print_word("type = "); | |
665 | _M_print_field(__formatter, "type"); | |
666 | ||
667 | if (_M_variant._M_iterator._M_constness != __unknown_constness) | |
668 | { | |
669 | __formatter->_M_print_word(" ("); | |
670 | _M_print_field(__formatter, "constness"); | |
671 | __formatter->_M_print_word(" iterator)"); | |
672 | } | |
673 | __formatter->_M_print_word(";\n"); | |
674 | } | |
285b36d6 | 675 | |
4be58168 BK |
676 | if (_M_variant._M_iterator._M_state != __unknown_state) |
677 | { | |
678 | __formatter->_M_print_word(" state = "); | |
679 | _M_print_field(__formatter, "state"); | |
680 | __formatter->_M_print_word(";\n"); | |
681 | } | |
285b36d6 | 682 | |
4be58168 BK |
683 | if (_M_variant._M_iterator._M_sequence) |
684 | { | |
685 | __formatter->_M_print_word(" references sequence "); | |
686 | if (_M_variant._M_iterator._M_seq_type) | |
687 | { | |
688 | __formatter->_M_print_word("with type `"); | |
689 | _M_print_field(__formatter, "seq_type"); | |
690 | __formatter->_M_print_word("' "); | |
691 | } | |
692 | ||
f18be892 | 693 | __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p\n", |
4be58168 | 694 | _M_variant._M_sequence._M_address); |
f18be892 | 695 | __formatter->_M_print_word(__buf); |
4be58168 BK |
696 | } |
697 | __formatter->_M_print_word("}\n"); | |
285b36d6 | 698 | } |
285b36d6 | 699 | else if (_M_kind == __sequence) |
285b36d6 | 700 | { |
4be58168 BK |
701 | __formatter->_M_print_word("sequence "); |
702 | if (_M_variant._M_sequence._M_name) | |
703 | { | |
f18be892 | 704 | __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ", |
4be58168 | 705 | _M_variant._M_sequence._M_name); |
f18be892 | 706 | __formatter->_M_print_word(__buf); |
4be58168 BK |
707 | } |
708 | ||
f18be892 | 709 | __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n", |
4be58168 | 710 | _M_variant._M_sequence._M_address); |
f18be892 | 711 | __formatter->_M_print_word(__buf); |
4be58168 BK |
712 | |
713 | if (_M_variant._M_sequence._M_type) | |
714 | { | |
715 | __formatter->_M_print_word(" type = "); | |
716 | _M_print_field(__formatter, "type"); | |
717 | __formatter->_M_print_word(";\n"); | |
718 | } | |
719 | __formatter->_M_print_word("}\n"); | |
285b36d6 | 720 | } |
285b36d6 BK |
721 | } |
722 | ||
723 | const _Error_formatter& | |
5d51b87a | 724 | _Error_formatter::_M_message(_Debug_msg_id __id) const throw () |
285b36d6 BK |
725 | { return this->_M_message(_S_debug_messages[__id]); } |
726 | ||
727 | void | |
728 | _Error_formatter::_M_error() const | |
729 | { | |
f18be892 PC |
730 | const int __bufsize = 128; |
731 | char __buf[__bufsize]; | |
285b36d6 BK |
732 | |
733 | // Emit file & line number information | |
734 | _M_column = 1; | |
735 | _M_wordwrap = false; | |
736 | if (_M_file) | |
4be58168 | 737 | { |
f18be892 PC |
738 | _M_format_word(__buf, __bufsize, "%s:", _M_file); |
739 | _M_print_word(__buf); | |
740 | _M_column += strlen(__buf); | |
4be58168 | 741 | } |
285b36d6 BK |
742 | |
743 | if (_M_line > 0) | |
4be58168 | 744 | { |
f18be892 PC |
745 | _M_format_word(__buf, __bufsize, "%u:", _M_line); |
746 | _M_print_word(__buf); | |
747 | _M_column += strlen(__buf); | |
4be58168 | 748 | } |
285b36d6 | 749 | |
5dddb7e5 PC |
750 | if (_M_max_length) |
751 | _M_wordwrap = true; | |
285b36d6 BK |
752 | _M_print_word("error: "); |
753 | ||
754 | // Print the error message | |
755 | assert(_M_text); | |
756 | _M_print_string(_M_text); | |
757 | _M_print_word(".\n"); | |
758 | ||
759 | // Emit descriptions of the objects involved in the operation | |
760 | _M_wordwrap = false; | |
f18be892 PC |
761 | bool __has_noninteger_parameters = false; |
762 | for (unsigned int __i = 0; __i < _M_num_parameters; ++__i) | |
285b36d6 | 763 | { |
f18be892 PC |
764 | if (_M_parameters[__i]._M_kind == _Parameter::__iterator |
765 | || _M_parameters[__i]._M_kind == _Parameter::__sequence) | |
4be58168 | 766 | { |
f18be892 | 767 | if (!__has_noninteger_parameters) |
4be58168 BK |
768 | { |
769 | _M_first_line = true; | |
770 | _M_print_word("\nObjects involved in the operation:\n"); | |
f18be892 | 771 | __has_noninteger_parameters = true; |
4be58168 | 772 | } |
f18be892 | 773 | _M_parameters[__i]._M_print_description(this); |
4be58168 | 774 | } |
285b36d6 | 775 | } |
285b36d6 BK |
776 | |
777 | abort(); | |
778 | } | |
779 | ||
9dc420e6 | 780 | template<typename _Tp> |
4be58168 BK |
781 | void |
782 | _Error_formatter::_M_format_word(char* __buf, | |
347669a0 | 783 | int __n __attribute__ ((__unused__)), |
5d51b87a | 784 | const char* __fmt, _Tp __s) const throw () |
4be58168 BK |
785 | { |
786 | #ifdef _GLIBCXX_USE_C99 | |
787 | std::snprintf(__buf, __n, __fmt, __s); | |
788 | #else | |
789 | std::sprintf(__buf, __fmt, __s); | |
790 | #endif | |
791 | } | |
792 | ||
793 | ||
285b36d6 BK |
794 | void |
795 | _Error_formatter::_M_print_word(const char* __word) const | |
796 | { | |
797 | if (!_M_wordwrap) | |
4be58168 BK |
798 | { |
799 | fprintf(stderr, "%s", __word); | |
800 | return; | |
801 | } | |
285b36d6 BK |
802 | |
803 | size_t __length = strlen(__word); | |
804 | if (__length == 0) | |
805 | return; | |
806 | ||
807 | if ((_M_column + __length < _M_max_length) | |
808 | || (__length >= _M_max_length && _M_column == 1)) | |
285b36d6 | 809 | { |
4be58168 BK |
810 | // If this isn't the first line, indent |
811 | if (_M_column == 1 && !_M_first_line) | |
812 | { | |
f18be892 | 813 | char __spacing[_M_indent + 1]; |
4be58168 | 814 | for (int i = 0; i < _M_indent; ++i) |
f18be892 PC |
815 | __spacing[i] = ' '; |
816 | __spacing[_M_indent] = '\0'; | |
817 | fprintf(stderr, "%s", __spacing); | |
4be58168 BK |
818 | _M_column += _M_indent; |
819 | } | |
820 | ||
821 | fprintf(stderr, "%s", __word); | |
822 | _M_column += __length; | |
823 | ||
824 | if (__word[__length - 1] == '\n') | |
825 | { | |
826 | _M_first_line = false; | |
827 | _M_column = 1; | |
828 | } | |
285b36d6 | 829 | } |
4be58168 | 830 | else |
285b36d6 | 831 | { |
285b36d6 | 832 | _M_column = 1; |
4be58168 BK |
833 | _M_print_word("\n"); |
834 | _M_print_word(__word); | |
285b36d6 | 835 | } |
285b36d6 BK |
836 | } |
837 | ||
838 | void | |
839 | _Error_formatter:: | |
840 | _M_print_string(const char* __string) const | |
841 | { | |
842 | const char* __start = __string; | |
1ab79481 | 843 | const char* __finish = __start; |
f18be892 PC |
844 | const int __bufsize = 128; |
845 | char __buf[__bufsize]; | |
285b36d6 BK |
846 | |
847 | while (*__start) | |
285b36d6 | 848 | { |
4be58168 BK |
849 | if (*__start != '%') |
850 | { | |
1ab79481 BK |
851 | // [__start, __finish) denotes the next word |
852 | __finish = __start; | |
853 | while (isalnum(*__finish)) | |
854 | ++__finish; | |
855 | if (__start == __finish) | |
856 | ++__finish; | |
857 | if (isspace(*__finish)) | |
858 | ++__finish; | |
4be58168 | 859 | |
1ab79481 | 860 | const ptrdiff_t __len = __finish - __start; |
8844a2f5 | 861 | assert(__len < __bufsize); |
b13de673 | 862 | memcpy(__buf, __start, __len); |
8844a2f5 | 863 | __buf[__len] = '\0'; |
f18be892 | 864 | _M_print_word(__buf); |
1ab79481 | 865 | __start = __finish; |
4be58168 BK |
866 | |
867 | // Skip extra whitespace | |
868 | while (*__start == ' ') | |
869 | ++__start; | |
870 | ||
871 | continue; | |
872 | } | |
285b36d6 | 873 | |
285b36d6 | 874 | ++__start; |
285b36d6 | 875 | assert(*__start); |
33d4e9b2 PC |
876 | if (*__start == '%') |
877 | { | |
878 | _M_print_word("%"); | |
879 | ++__start; | |
880 | continue; | |
881 | } | |
882 | ||
883 | // Get the parameter number | |
884 | assert(*__start >= '1' && *__start <= '9'); | |
f18be892 PC |
885 | size_t __param = *__start - '0'; |
886 | --__param; | |
887 | assert(__param < _M_num_parameters); | |
285b36d6 | 888 | |
33d4e9b2 PC |
889 | // '.' separates the parameter number from the field |
890 | // name, if there is one. | |
891 | ++__start; | |
892 | if (*__start != '.') | |
893 | { | |
894 | assert(*__start == ';'); | |
895 | ++__start; | |
f18be892 PC |
896 | __buf[0] = '\0'; |
897 | if (_M_parameters[__param]._M_kind == _Parameter::__integer) | |
33d4e9b2 | 898 | { |
f18be892 PC |
899 | _M_format_word(__buf, __bufsize, "%ld", |
900 | _M_parameters[__param]._M_variant._M_integer._M_value); | |
901 | _M_print_word(__buf); | |
33d4e9b2 | 902 | } |
f18be892 PC |
903 | else if (_M_parameters[__param]._M_kind == _Parameter::__string) |
904 | _M_print_string(_M_parameters[__param]._M_variant._M_string._M_value); | |
33d4e9b2 PC |
905 | continue; |
906 | } | |
907 | ||
908 | // Extract the field name we want | |
f18be892 PC |
909 | enum { __max_field_len = 16 }; |
910 | char __field[__max_field_len]; | |
911 | int __field_idx = 0; | |
33d4e9b2 PC |
912 | ++__start; |
913 | while (*__start != ';') | |
914 | { | |
915 | assert(*__start); | |
f18be892 PC |
916 | assert(__field_idx < __max_field_len-1); |
917 | __field[__field_idx++] = *__start++; | |
33d4e9b2 PC |
918 | } |
919 | ++__start; | |
f18be892 | 920 | __field[__field_idx] = 0; |
33d4e9b2 | 921 | |
f18be892 | 922 | _M_parameters[__param]._M_print_field(this, __field); |
33d4e9b2 | 923 | } |
285b36d6 | 924 | } |
4be58168 | 925 | |
5dddb7e5 | 926 | void |
5d51b87a | 927 | _Error_formatter::_M_get_max_length() const throw () |
5dddb7e5 PC |
928 | { |
929 | const char* __nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH"); | |
930 | if (__nptr) | |
931 | { | |
932 | char* __endptr; | |
933 | const unsigned long __ret = std::strtoul(__nptr, &__endptr, 0); | |
934 | if (*__nptr != '\0' && *__endptr == '\0') | |
935 | _M_max_length = __ret; | |
936 | } | |
937 | } | |
938 | ||
4be58168 BK |
939 | // Instantiations. |
940 | template | |
941 | void | |
347669a0 BK |
942 | _Error_formatter::_M_format_word(char*, int, const char*, |
943 | const void*) const; | |
4be58168 BK |
944 | |
945 | template | |
946 | void | |
347669a0 | 947 | _Error_formatter::_M_format_word(char*, int, const char*, long) const; |
4be58168 BK |
948 | |
949 | template | |
950 | void | |
347669a0 BK |
951 | _Error_formatter::_M_format_word(char*, int, const char*, |
952 | std::size_t) const; | |
4be58168 BK |
953 | |
954 | template | |
955 | void | |
347669a0 BK |
956 | _Error_formatter::_M_format_word(char*, int, const char*, |
957 | const char*) const; | |
285b36d6 | 958 | } // namespace __gnu_debug |