This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[libstdc++ PATCH] libstdc++ debug mode (second try)
- From: Doug Gregor <dgregor at apple dot com>
- To: libstdc++ at gcc dot gnu dot org
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Fri, 18 Jul 2003 09:02:03 -0700
- Subject: [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).
Doug
2003-07-18 Doug Gregor <dgregor@apple.com>
* Makefile.am: Optionally recurse into 'debug' subdir.
* configure.in: Generate debug/Makefile.
* docs/html/debug.html: Document libstdc++ debug mode.
* docs/html/17_intro/howto.html: Document debug-mode macros.
* include/Makefile.am: Install debug-mode headers.
* src/Makefile.am: Include debug.cc.
* 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
annotations.
* include/bits/stl_algobase.h: Ditto.
* include/ext/algorithm: Ditto.
* testsuite/Makefile.am: 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
library.
* testsuite/23_containers/list_operators.cc: Don't verify
performance guarantees when in debug mode.
* testsuite/23_containers/bitset_inval.cc: New.
* testsuite/23_containers/deque_inval.cc: New.
* testsuite/23_containers/list_inval.cc: New.
* testsuite/23_containers/map_inval.cc: New.
* testsuite/23_containers/multimap_inval.cc: New.
* testsuite/23_containers/multiset_inval.cc: New.
* testsuite/23_containers/set_inval.cc: New.
* testsuite/23_containers/vector_inval.cc: 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/debug.cc: New.
Attachment:
debugmode.patch.gz
Description: GNU Zip compressed data
Attachment:
linkname.patch
Description: Binary data