STLport.org - "Templates that fit"
Contents
Introduction
  About STLport
  SGI STL Base
  STLport Story

STLport Features
  Portability
  Debug Mode
  Thread Safety
  Exception Safety

Getting Started
  Download and Install
  Select Streams Mode
  Compiling with STLport

White Papers
  Release Notes
  READMEs
  Interface with std::
  Wrappers
  Config manual
  Regression Test
  Exception Test

Feedback
  Bug Reports
  Forum

Appendix
  Acknowledgements
  Your Free Licence

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 __STL_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__STL_DEBUG foo.cpp

Naturally, you may also wrap it into your project configuration header :

# ifdef _NDEBUG
# undef __STL_DEBUG
# else
# define __STL_DEBUG 1
# endif

Important : you must recompile your project after changing __STL_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 __STL_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 __STL_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.

Copyright � 1999,2000 by Boris Fomitchev.    Last modified: July 14, 2000