STLport : Debug Mode
by Boris Fomitchev
Abstract
Debug mode lets you find very obscure bugs in application code which uses STL iterators and algorithms.
It performs runtime checking of iterator validity and ownership and algorithm
preconditions.
When debug check reveals the bug, it terminates the program
with detailed diagnostics.
STLport in debug mode is as much exception-safe and
thread-safe as in release mode.
Debugging facilities provided
- "Safe iterators" for all STL containers.
They report detailed diagnostics when being used in invalid ways.
- Checking of preconditions for algorithms and container methods.
STLport checks the following reasonable set of preconditions:
- Range preconditions for random-access iterators
- Iterator's ownership, validity and deferenceability
- Container-specific preconditions for methods
Implementation
Checked iterators keep track of their container while the container
keeps track of them. The idea was introduced in Cay
Horstmann's "Safe STL".
- If the container goes out of scope, its iterators are being
invalidated;
- If certain iterators are being invalidated because of mutating
operation, all instances of this iterator are invalidated.
Usage
To turn on the debug mode, you should somehow #define _STLP_DEBUG
macro before including any STL header. You can either supply the
definition via compiler command-line or within CXXFLAGS in your makefile:
$> CC -g -D_STLP_DEBUG foo.cpp
Naturally, you may also wrap it into your project configuration
header :
# ifdef _NDEBUG
# undef _STLP_DEBUG
# else
# define _STLP_DEBUG 1
# endif
Important : you must recompile your project after changing _STLP_DEBUG
definition.
Examples
Here are some error examples with corresponding runtime output:
char string[23] = "A string to be copied.";
char result[23];
copy(string+20, string+10, result);
_debug.h:168 STL error : Range [first,last) is invalid
algobase.h:369 STL assertion failure: __check_range(first, last)
vector<char>::iterator i;
char ii = *i;
stldebug.h:152 STL error : Uninitialized or invalidated (by
mutating operation) iterator used
vector.h:158 STL assertion failure: __check_dereferenceable(*this)
vector<char>::iterator i=v2.begin();
v2.insert(v2.begin(),'!');
char ii = *i;
_debug.h:152 STL error : Uninitialized or invalidated (by
mutating operation) iterator used
vector.h:158 STL assertion failure: __check_dereferenceable(*this)
vector<int> v; v.pop_back();
vector.h:482 STL error : Trying to extract an object out from
empty container
vector.h:482 STL assertion failure: !empty()
vector <int> v1(10);
for(int i = 0; i < v1.size(); i++)
v1[i] = i; vector <int> v2(10);
copy(v1.begin(), .end(), v2.begin());
_debug.h:61 STL error : Iterators used in expression are from
different owners
vector.h:182 STL assertion failure: __check_same_owner(*this,y)
list<int> l1(array1, array1 + 3);
l1.erase(l1.end());
list.h:398 STL error : Past-the-end iterator could not be erased
list.h:398 STL assertion failure: position.node!=node
list<int> l1(array1, array1 + 3);
list<int> l2(array2, array2 + 2);
l1.erase(l2.begin());
_debug.h:70 STL error : Container doesn't own the iterator
list.h:397 STL assertion failure: __check_if_owner(node,position)
Notes
- Application code using T* to store vector::iterator
would not compile in debug mode. Such code should be fixed - the
standard does not specify vector::iterator, so different implementations
can use different types for it.
- Miscellanous stuff used by debug engine (_debug.h) is
not documented on purpose. Never explicitly include or otherwise use
it in your code - it's non-standard and is subject to change.
- The ability to throw exceptions instead of calling abort()
is provided since 3.2. Please comment out _STLP_NO_DEBUG_EXCEPTIONS switch which
disables it as default.
- If those two defaults do not match your debugging needs,
you may force all failed assertions to be executed through user-defined global function:
void __stl_debug_terminate(void). This allows you to take control of assertion behavior for debugging purposes.
- You can control the way the debug checking messages are being printed out by defining
your own debug output function. To do so, you should define _STLP_DEBUG_MESSAGE switch in stl_user_config.h and
provide your function with the following signature :
void __stl_debug_message(const char * format_str, ...). The parameters are printf()-like.
STLport will then use it to format debug message output.
- Some preconditions that cannot be checked without partial class
template specialization still left alone. (example : for
copy(InputIterator first, InputIterator last, OutputIterator result)
algorithm, result should not be in range [first,last). )
- Unfortunately, the file/line pairs reported by debug engine always
point to STL code, not to application code. I see no way to fix that
( although the diagnostic certainly may be refined ). There's
no substitute for good debugger to walk up the stack and locate the
error.
|