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