C plus plus:Modern C plus plus:Appendices:Checked std::lib

From GPWiki
Jump to: navigation, search

Modern C++ : Going Beyond "C with Classes"

Introduction

I've mentioned a "Checked std::lib" implementation a few times, but it's important enough that I think it deserves an example.

The Code

// file: cxdbg.cpp

  1. include <vector>
  2. include <iostream>

using namespace std;

int main() {

   vector<int> v(1);
   cout << *v.end() << endl;

}

Compiled Normally

me22@me22gentoo ~/programming $ g++ cxdbg.cpp
me22@me22gentoo ~/programming $ ./a.out
0

Undefined behaviour, but no errors. Good luck realising that in the middle of a huge application.

Compiled Checked

me22@me22gentoo ~/programming $ g++ cxdbg.cpp -D_GLIBCXX_DEBUG
me22@me22gentoo ~/programming $ ./a.out
/usr/lib/gcc/i686-pc-linux-gnu/4.1.1/include/g++-v4/debug/safe_iterator.h:181:
    error: attempt to dereference a past-the-end iterator.

Objects involved in the operation:
iterator "this" @ 0x0xbfbe52dc {
type = N11__gnu_debug14_Safe_iteratorIN9__gnu_cxx17__normal_iteratorIPiN10__gnu_norm6vectorIiSaIiEEEEEN15__gnu_debug_def6vectorIiS6_EEEE (mutable iterator);
  state = past-the-end;
  references sequence with type `N15__gnu_debug_def6vectorIiSaIiEEE' @ 0x0xbfbe52dc
}
Aborted

Much better. It doesn't tell us exactly where the problem is, but we know without a doubt that something made an "attempt to dereference a past-the-end iterator" and a big of puzzling over the mangled names will tell us it's an iterator into a vector. If you'd rather not puzzle, you can get a name demangler that'll find the real type.

Using a Debugger

Of course, puzzling and guessing is annoying. That "Aborted" at the bottom of the output came from calling abort, so let's try throwing the debugger at it:

me22@me22gentoo ~/programming $ g++ cxdbg.cpp -D_GLIBCXX_DEBUG -ggdb
me22@me22gentoo ~/programming $ gdb ./a.out
GNU gdb 6.4
Copyright 2005 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".

(gdb) run
Starting program: /home/me22/programming/a.out
/usr/lib/gcc/i686-pc-linux-gnu/4.1.1/include/g++-v4/debug/safe_iterator.h:181:
    error: attempt to dereference a past-the-end iterator.

Objects involved in the operation:
iterator "this" @ 0x0xbfce0bac {
type = N11__gnu_debug14_Safe_iteratorIN9__gnu_cxx17__normal_iteratorIPiN10__gnu_norm6vectorIiSaIiEEEEEN15__gnu_debug_def6vectorIiS6_EEEE (mutable iterator);
  state = past-the-end;
  references sequence with type `N15__gnu_debug_def6vectorIiSaIiEEE' @ 0x0xbfce0bac
}

Program received signal SIGABRT, Aborted.
0xffffe410 in __kernel_vsyscall ()
(gdb) backtrace
#0  0xffffe410 in __kernel_vsyscall ()
#1  0xb7d46620 in raise () from /lib/libc.so.6
#2  0xb7d47c80 in abort () from /lib/libc.so.6
#3  0xb7eb084d in __gnu_debug::_Error_formatter::_M_error ()
   from /usr/lib/gcc/i686-pc-linux-gnu/4.1.1/libstdc++.so.6
#4  0x0804a456 in __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<int*, __gnu_norm::vector<int, std::allocator<int> > >, __gnu_debug_def::vector<int, std::allocator<int> > >::operator* (this=0xbfce0bac) at safe_iterator.h:179
#5  0x08049417 in main () at cxdbg.cpp:9

Even better! We still get the same message, but the backtrace means no puzzling over the mangled name. Additionally, the last line of the backtrace tells us exactly where the problem is and we already know what the problem is, so it should be a cinch to fix.

In Closing

Remember to turn this off during performance tuning, but anything that can find bugs for you without you having to do anything is always welcome.

External Links