This is the mail archive of the mailing list for the libstdc++ project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[libstdc++ PATCH] libstdc++ debug mode (second try)

This is my second attempt at the libstdc++ debug mode patch. Here is the capsule summary of the changes; read on for information on testing the patch.

	* No need to build/link against libstdc++-debug.
	* Merge __is_null_pointer back into basic_string.tcc (and
	removed gnu-cxx-utility.h).
	* Make macro naming scheme fit with libstdc++.
	* Added some missing copyright/license headers.
	* Move all debug-mode headers into include/debug/.
	* Release-mode debugging containers are now in __gnu_debug.
	* Necessary documentation updates.
	* Fixed a bug in _Safe_sequence::_M_invalidate_if.
	* Fix transfer of iterators in list::splice().
	* Add invalidation tests.

=== To test the patch ===
Apply this patch and also my link_name patch (attached, but will be submitted in full separately). No need to configure libstdc++ with --enable-libstdcxx-debug; just compile with -D_GLIBCXX_DEBUG.

=== Why no libstdc++-debug.(so|a)? ===
The first version of this patch built a separate library libstdc++-debug; executables compiled with the debug mode linked against this library in lieu of libstdc++. However, the two libraries could never be linked into the same program without causing serious trouble. This behavior is unfortunate and undesirable enough to push us to consider giving up a little on the checking side to make the debug mode easier to use.

What we gave up: safe iterators for std::basic_string<...>.

What we gained: the ability to mix debug-mode--compiled code with release-mode--compiled code, so long as one doesn't share an entity compiled with both debug and release modes.

==== Why no basic_string? ====
Most of the C++ standard library containers are user facilities only, and aren't reused in any other part of the library for any public interface. Strings, however, are pervasive, especially in locales. In locales, strings are used in the worst way possible from a debug/release-mode compatibility perspective: they are returned from virtual functions in a public interface. Since the debug mode operates by adding more information into containers & iterators (namely, references between the two), the size of std::basic_string needs to change from release to debug mode. However, with a virtual function returning a string, which string type is returned in a mixed debug/release program? (And remember that locales are part of the global state!). To further compound the problem, return types aren't part of the name-mangling scheme, so one won't even get a link error if the wrong string type is used.

To circumvent the problem, we chose to eliminate safe iterators for strings.

==== Mixing debug/non-debug code and the link_name patch ====
Even with the elimination of strings, we still have a problem with standard library types changing sizes in debug mode versus release mode. For instance, if we instantiate std::vector<int> in translation unit A compiled with debug mode and then instantiate std::vector<int> in translation unit B compiled with release mode, we have an ODR violation. But we want it to work, because it will help users, so we find a way to make the ODR violation _not_ cause real problems. There is no alias mechanism in C++ for templates, so both std::vector<int>'s really are std::vector<int> and will mangle the same way.

Enter link_name: the link_name patch introduces a new type attribute "link_name" that specifies a different name from the type name to use during name mangling. For instance, consider the following code:

  class __attribute__((__link_name__("bar"))) foo { };
  class bar { };

  void do_it(const foo&) { }
  void do_it(const bar&) { }

When we mangle the class "foo", it mangles with the name "bar" instead of foo. If one tries to compile this code, we'll get a duplicate definition error on do_it, because class foo (with link_name "bar") mangles in the exact same way as class bar does. We use this link_name trick to turn an ODR violation into something safer.

In release mode there are no link_name attributes, so std::list mangles as std::list. No change here from previous behavior.

In debug mode, we have both debug and release containers around, and std::list is the debug container. We note that the release container is exactly equivalent to the container in release mode. That's _very_ important. The two containers are:

release container: the container name is prefixed with _Release_, so the std::list from release mode is named std::_Release_list in debug mode. However, the link_name attribute sets the link name to "list" to match what's in release mode. So from a linking perspective, the release-mode std::list and the debug-mode std::_Release_list are actually equivalent.

debug container: the container name is retained (e.g., std::list), because this is the container the user sees. The link_name is then set to "_Debug_list", so it mangles differently from the release-mode container.

The code looks a little like this:

template<typename _Tp, typename _Allocator = std::allocator<_Tp> >
class __attribute__((__link_name__("list"))) _Release_list { /* ... */ };

  template<typename _Tp, typename _Allocator = std::allocator<_Tp> >
    class __attribute__((__link_name__("_Debug_list"))) list
    : public _Release_list<_Tp, _Allocator>
    { /* ... */ };

Advantages of this scheme:
* Debug/non-debug compatibility.
* Link errors if one tries to link debug/non-debug units in an unsafe way.
* Only one standard library.

Disadvantages of this scheme:
* Don't have full checking of std::basic_string<...> in debug mode (but we may be able to get close!).
* May be considered a hack.
* In very rare circumstances (e.g., function returning a vector<int> but vector<int> otherwise unused in the translation unit), won't trigger link errors when debug/non-debug compatibility is abused.

=== Wrapup ===
Tested on i686-pc-linux-gnu and powerpc-apple-darwin; no regressions compiling libstdc++ testsuite in either debug mode or release mode on either platform. New iterator invalidation tests pass on both platforms in both debug mode and release mode.

Change log for the debug mode follows. The link_name change log will be submitted with the full link_name patch (later today, I hope).


2003-07-18 Doug Gregor <>

        * Optionally recurse into 'debug' subdir.
        * Generate debug/Makefile.
        * docs/html/debug.html: Document libstdc++ debug mode.
        * docs/html/17_intro/howto.html: Document debug-mode macros.
        * include/ Install debug-mode headers.
        * src/ Include
        * include/bits/basic_string.tcc:
          (basic_string::_S_construct): Fix NULL pointer check.
          (__is_null_pointer): New.
        * include/bits/deque.tcc: Prefix class name with _Release_ when
        in debug mode.
        Mark the class as a release-mode class.
        * include/bits/istream.tcc: Ditto.
        * include/bits/list.tcc: Ditto.
        * include/bits/ostream.tcc: Ditto.
        * include/bits/stl_bvector.h: Ditto.
        * include/bits/stl_deque.h: Ditto.
        * include/bits/stl_list.h: Ditto.
        * include/bits/stl_map.h: Ditto.
        * include/bits/stl_multimap.h: Ditto.
        * include/bits/stl_multiset.h: Ditto.
        * include/bits/stl_set.h: Ditto.
        * include/bits/stl_vector.h: Ditto.
        * include/bits/vector.tcc: Ditto.
        * include/ext/hash_map: Ditto.
        * include/ext/hash_set: Ditto.
        * include/std/std_bitset.h: Ditto.
        * include/bits/stl_algo.h: Added algorithm precondition
        * include/bits/stl_algobase.h: Ditto.
        * include/ext/algorithm: Ditto.
        * testsuite/ Build a debug version of the testing
        support library.
        * testsuite/lib/libstdc++-v3-dg.exp: When compiling with
        -D_GLIBCXX_DEBUG, link against debug version of testing support
        * testsuite/23_containers/ Don't verify
        performance guarantees when in debug mode.
        * testsuite/23_containers/ New.
        * testsuite/23_containers/ New.
        * testsuite/23_containers/ New.
        * testsuite/23_containers/ New.
        * testsuite/23_containers/ New.
        * testsuite/23_containers/ New.
        * testsuite/23_containers/ New.
        * testsuite/23_containers/ New.
        * include/debug/bitset: New.
        * include/debug/dbg_bitset.h: New.
        * include/debug/dbg_deque.h: New.
        * include/debug/dbg_hash_map.h: New.
        * include/debug/dbg_hash_multimap.h: New.
        * include/debug/dbg_hash_multiset.h: New.
        * include/debug/dbg_hash_set.h: New.
        * include/debug/dbg_list.h: New.
        * include/debug/dbg_map.h: New.
        * include/debug/dbg_multimap.h: New.
        * include/debug/dbg_multiset.h: New.
        * include/debug/dbg_set.h: New.
        * include/debug/dbg_vector.h: New.
        * include/debug/debug.h: New.
        * include/debug/deque: New.
        * include/debug/formatter.h: New.
        * include/debug/hash_map: New.
        * include/debug/hash_set: New.
        * include/debug/list: New.
        * include/debug/map: New.
        * include/debug/safe_base.h: New.
        * include/debug/safe_iterator.h: New.
        * include/debug/safe_iterator.tcc: New.
        * include/debug/safe_sequence.h: New.
        * include/debug/set: New.
        * include/debug/string: New.
        * include/debug/support.h: New.
        * include/debug/vector: New.
        * src/ New.

Attachment: debugmode.patch.gz
Description: GNU Zip compressed data

Attachment: linkname.patch
Description: Binary data

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]