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(), v2.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.

Table of Contents


Copyright 2001 by STLport