Index: config/linker-map.gnu =================================================================== RCS file: /cvs/gcc/gcc/libstdc++-v3/config/linker-map.gnu,v retrieving revision 1.46 diff -c -3 -p -r1.46 linker-map.gnu *** config/linker-map.gnu 30 Jul 2003 15:01:58 -0000 1.46 --- config/linker-map.gnu 13 Aug 2003 18:42:33 -0000 *************** GLIBCXX_3.4 { *** 57,63 **** std::__num_base::_S_atoms_out; std::__moneypunct_cache*; std::__numpunct_cache*; ! std::__timepunct_cache* }; # Names not in an 'extern' block are mangled names. --- 57,66 ---- std::__num_base::_S_atoms_out; std::__moneypunct_cache*; std::__numpunct_cache*; ! std::__timepunct_cache*; ! __gnu_debug::_Safe_iterator_base*; ! __gnu_debug::_Safe_sequence_base*; ! __gnu_debug::_Error_formatter* }; # Names not in an 'extern' block are mangled names. Index: docs/html/17_intro/howto.html =================================================================== RCS file: /cvs/gcc/gcc/libstdc++-v3/docs/html/17_intro/howto.html,v retrieving revision 1.30 diff -c -3 -p -r1.30 howto.html *** docs/html/17_intro/howto.html 28 Jul 2003 04:13:58 -0000 1.30 --- docs/html/17_intro/howto.html 13 Aug 2003 18:42:33 -0000 *************** *** 339,344 **** --- 339,356 ---- violations of the requirements of the standard. This is described in more detail here. +
_GLIBCXX_DEBUG_GLIBCXX_DEBUG_PEDANTICThe libstdc++ debug mode replaces unsafe (but efficient) standard + containers and iterators with semantically equivalent safe standard + containers and iterators to aid in debugging user programs. The + following goals directed the design of the libstdc++ debug mode:
+ +std::vector<int>) compiled in release
+ mode can be linked against a translation unit B that
+ contains the same instantiation compiled in debug mode (a
+ feature not present with partial recompilation). While this
+ behavior is technically a violation of the One Definition
+ Rule, this ability tends to be very important in
+ practice. The libstdc++ debug mode supports this level of
+ recompilation. -g mode",
+ because the -g compiler switch works in this way,
+ emitting debugging information at a per--translation-unit
+ granularity. We believe that this level of recompilation is in
+ fact not possible if we intend to supply safe iterators, leave
+ the program semantics unchanged, and not regress in
+ performance under release mode because we cannot associate
+ extra information with an iterator (to form a safe iterator)
+ without either reserving that space in release mode
+ (performance regression) or allocating extra memory associated
+ with each iterator with new (changes the program
+ semantics).There are several existing implementations of debug modes for C++ + standard library implementations, although none of them directly + supports debugging for programs using libstdc++. The existing + implementations include:
+This section provides an overall view of the design of the + libstdc++ debug mode and details the relationship between design + decisions and the stated design goals.
+ +The libstdc++ debug mode uses a wrapper model where the debugging + versions of library components (e.g., iterators and containers) form + a layer on top of the release versions of the library + components. The debugging components first verify that the operation + is correct (aborting with a diagnostic if an error is found) and + will then forward to the underlying release-mode container that will + perform the actual work. This design decision ensures that we cannot + regress release-mode performance (because the release-mode + containers are left untouched) and partially enables mixing debug and release code at link time, + although that will not be discussed at this time.
+ +Two types of wrappers are used in the implementation of the debug + mode: container wrappers and iterator wrappers. The two types of + wrappers interact to maintain relationships between iterators and + their associated containers, which are necessary to detect certain + types of standard library usage errors such as dereferencing + past-the-end iterators or inserting into a container using an + iterator from a different container.
+ +Iterator wrappers provide a debugging layer over any iterator that
+ is attached to a particular container, and will manage the
+ information detailing the iterator's state (singular,
+ dereferenceable, etc.) and tracking the container to which the
+ iterator is attached. Because iterators have a well-defined, common
+ interface the iterator wrapper is implemented with the iterator
+ adaptor class template __gnu_debug::_Safe_iterator,
+ which takes two template parameters:
Iterator: The underlying iterator type, which must
+ be either the iterator or const_iterator
+ typedef from the sequence type this iterator can reference.Sequence: The type of sequence that this iterator
+ references. This sequence must be a safe sequence (discussed below)
+ whose iterator or const_iterator typedef
+ is the type of the safe iterator.Container wrappers provide a debugging layer over a particular
+ container type. Because containers vary greatly in the member
+ functions they support and the semantics of those member functions
+ (especially in the area of iterator invalidation), container
+ wrappers are tailored to the container they reference, e.g., the
+ debugging version of std::list duplicates the entire
+ interface of std::list, adding additional semantic
+ checks and then forwarding operations to the
+ real std::list (a public base class of the debugging
+ version) as appropriate. However, all safe containers inherit from
+ the class template __gnu_debug::_Safe_sequence,
+ instantiated with the type of the safe container itself (an instance
+ of the curiously recurring template pattern).
The iterators of a container wrapper will be + safe iterators that reference sequences + of this type and wrap the iterators provided by the release-mode + base class. The debugging container will use only the safe + iterators within its own interface (therefore requiring the user to + use safe iterators, although this does not change correct user + code) and will communicate with the release-mode base class with + only the underlying, unsafe, release-mode iterators that the base + class exports.
+ + The debugging version of std::list will have the
+ following basic structure:
+ template<typename _Tp, typename _Allocator = std::allocator<_Tp>
+ class debug-list :
+ public release-list<_Tp, _Allocator>,
+ public __gnu_debug::_Safe_sequence<debug-list<_Tp, _Allocator> >
+ {
+ typedef release-list<_Tp, _Allocator> _Base;
+ typedef debug-list<_Tp, _Allocator> _Self;
+
+ public:
+ typedef __gnu_debug::_Safe_iterator<typename _Base::iterator, _Self> iterator;
+ typedef __gnu_debug::_Safe_iterator<typename _Base::const_iterator, _Self> const_iterator;
+
+ // duplicate std::list interface with debugging semantics
+ };
+
+
+ The debug mode operates primarily by checking the preconditions of
+ all standard library operations that it supports. Preconditions that
+ are always checked (regardless of whether or not we are in debug
+ mode) are checked via the __check_xxx macros defined
+ and documented in the source
+ file include/debug/debug.h. Preconditions that may or
+ may not be checked, depending on the debug-mode
+ macro _GLIBCXX_DEBUG, are checked via
+ the __requires_xxx macros defined and documented in the
+ same source file. Preconditions are validated using any additional
+ information available at run-time, e.g., the containers that are
+ associated with a particular iterator, the position of the iterator
+ within those containers, the distance between two iterators that may
+ form a valid range, etc. In the absence of suitable information,
+ e.g., an input iterator that is not a safe iterator, these
+ precondition checks will silently succeed.
The majority of precondition checks use the aforementioned macros,
+ which have the secondary benefit of having prewritten debug
+ messages that use information about the current status of the
+ objects involved (e.g., whether an iterator is singular or what
+ sequence it is attached to) along with some static information
+ (e.g., the names of the function parameters corresponding to the
+ objects involved). When not using these macros, the debug mode uses
+ either the debug-mode assertion
+ macro _GLIBCXX_DEBUG_ASSERT , its pedantic
+ cousin _GLIBCXX_DEBUG_PEDASSERT, or the assertion
+ check macro that supports more advance formulation of error
+ messages, _GLIBCXX_DEBUG_VERIFY. These macros are
+ documented more thoroughly in the debug mode source code.
The libstdc++ debug mode is the first debug mode we know of that + is able to provide the "Per-use recompilation" (4) guarantee, that + allows release-compiled and debug-compiled code to be linked and + executed together without causing unpredictable behavior. This + guarantee minimizes the recompilation that users are required to + perform, shortening the detect-compile-debug bughunting cycle + and making the debug mode easier to incorporate into development + environments by minimizing dependencies.
+ +Achieving link- and run-time coexistence is not a trivial
+ implementation task. To achieve this goal we required a small
+ extension to the GNU C++ compiler (described in the section on
+ link- and run-time coexistence) and complex
+ organization of debug- and release-modes. The end result is that we
+ have achieved per-use recompilation but have had to give up some
+ checking of the std::basic_string class template
+ (namely, safe iterators).
+
+
Both the release-mode components and the debug-mode
+ components need to exist within a single translation unit so that
+ the debug versions can wrap the release versions. However, only one
+ of these components should be user-visible at any particular
+ time with the standard name, e.g., std::list. In
+ release mode, we define only the release-mode version of the
+ component with its standard name and do not include the debugging
+ component at all (except, perhaps, in __gnu_debug, if
+ requested via the separate debugging headers). This method leaves the
+ behavior of release mode completely unchanged from its behavior
+ prior to the introduction of the libstdc++ debug mode.
In debug mode we include the release-mode container into its
+ natural namespace but perform renaming to an implementation-defined
+ name using preprocessor macros. Thus the
+ release-mode std::list will be renamed
+ to std::_Release_list during debug mode, and we will
+ automatically include the debugging version with the
+ name std::list for users to reference. This method
+ allows the debug- and release-mode versions of the same component to
+ coexist at compile-time without causing an unreasonable maintenance
+ burden.
There is a problem with the simple compile-time coexistence + mechanism: if a user compiles some modules with release mode and + some modules with debug mode, the debuggable components will differ + in different translation units, violating the C++ One Definition + Rule (ODR). This violation will likely be detected at link time, + because the sizes of debug-mode containers will differ from the + sizes of release-mode containers, although in some cases (such as + dynamic linking) the error may be detected much later (or not at + all!).
+ +Unfortunately, it is not possible to avoid violating the ODR with
+ most debug mode designs (see the section on alternatives for coexistence), so the
+ philosophy of the libstdc++ debug mode is to acknowledge that there
+ is an unavoidable ODR violation in this case but to ensure that the
+ ODR violation does not affect execution. To accomplish this, the
+ libstdc++ debug mode uses the aforementioned preprocessor renaming
+ scheme but includes an additional renaming scheme that happens at
+ compile-time that essentially reverses the preprocessor
+ renaming from the linker's point of view. Thus, in debug
+ mode, the release-mode list container is
+ named std::_Release_list but will be mangled with the
+ name std::list (as it was in release mode). Similarly,
+ the debug-mode list is named std::list
+ (in debug mode) but will be mangled
+ as std::_Debug_list. Thus the
+ release-mode list always compiles down to code that
+ uses the name std::list, and the
+ debug-mode list always compiles down to code that uses
+ the name std::_Debug_list, independent of the use of
+ debug mode. This has several positive effects:
The new link_name class attribute facilities
+ renaming. It may be attached to any class type (or any class
+ template) to override the name of the class used for name
+ mangling. For instance, a class named bar would
+ generally mangle as 3bar; if the class has
+ a link_name attribute that specifies the string
+ "wibble", then it would mangle as 6wibble.
Note that although we have hidden the ODR violation, it still
+ exists. For this reason we cannot easily provide safe iterators for
+ the std::basic_string class template, as it is present
+ throughout the C++ standard library. For instance, locale facets
+ define typedefs that include basic_string: in a mixed
+ debug/release program, should that typedef be based on the
+ debug-mode basic_string or the
+ release-mode basic_string? While the answer could be
+ "both", and the difference hidden via renaming a la the
+ debug/release containers, we must note two things about locale
+ facets:
With the design of libstdc++ debug mode, we cannot effectively hide
+ the differences between debug and release-mode strings from the
+ user. Failure to hide the differences may result in unpredictable
+ behavior, and for this reason we have opted to only
+ perform basic_string changes that do not require ABI
+ changes. The effect on users is expected to be minimal, as there are
+ simple alternatives (e.g., __gnu_debug::basic_string),
+ and the usability benefit we gain from the ability to mix debug- and
+ release-compiled translation units is enormous.
The coexistence scheme was chosen over many alternatives, + including language-only solutions and solutions that also required + extensions to the C++ front end. The following is a partial list of + solutions, with justifications for our rejection of each.
+ +Debug boolean template parameter:
+ Partial specialization could be used to select the debug
+ implementation when Debug == true, and the state
+ of _GLIBCXX_DEBUG could decide whether the
+ default Debug argument is true
+ or false. This option would break conformance with the
+ C++ standard in both debug and release modes. This would
+ not meet our correctness criteria. Allocator template parameter of containers
+ by adding a sentinel wrapper debug<> that
+ signals the user's intention to use debugging, and pick up
+ the debug&lr;> allocator wrapper in a partial
+ specialization. However, this has two drawbacks: first, there is a
+ conformance issue because the default allocator would not be the
+ standard-specified std::allocator<T>. Secondly
+ (and more importantly), users that specify allocators instead of
+ implicitly using the default allocator would not get debugging
+ containers. Thus this solution fails the correctness
+ criteria.using declaration (or directive): This is an
+ enticing option, because it would eliminate the need for
+ the link_name extension by aliasing the
+ templates. However, there is no true template aliasing mechanism
+ is C++, because both using directives and using
+ declarations disallow specialization. This method fails
+ the correctness criteria.link_name solution, eliminated
+ only because it requires more extensive compiler changes
+ than link_name. In this model, we would define the
+ debug containers in a different namespace
+ (e.g., __gnu_debug) and then import them (e.g., with
+ an extended using declaration that aliases templates,
+ such as that of template
+ aliases proposal). This solution is workable, and in fact
+ would be desirable in the long run, but requires a sizeable change
+ to the C++ compiler front-end that is not within the scope of
+ this project.std to an internal namespace, such
+ as __gnu_std_debug, so that it is completely
+ separate from the release-mode std namespace. While
+ this will solve some renaming problems and ensure that
+ debug- and release-compiled code cannot be mixed unsafely, it ensures that
+ debug- and release-compiled code cannot be mixed at all. For
+ instance, the program would have two std::cout
+ objects! This solution would fails the minimize
+ recompilation requirement, because we would only be able to
+ support option (1) or (2).Other options may exist for implementing the debug mode, many of
+ which have probably been considered and others that may still be
+ lurking. This list may be expanded over time to include other
+ options that we could have implemented, but in all cases the full
+ ramifications of the approach (as measured against the design goals
+ for a libstdc++ debug mode) should be considered first. The DejaGNU
+ testsuite includes some testcases that check for known problems with
+ some solutions (e.g., the using declaration solution
+ that breaks user specialization), and additional testcases will be
+ added as we are able to identify other typical problem cases. These
+ test cases will serve as a benchmark by which we can compare debug
+ mode implementations.
+ See license.html for copying conditions. + Comments and suggestions are welcome, and may be sent to + the libstdc++ mailing list. +
+ + +