From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libstdc++-v3/doc/html/manual/bk01pt03ch17s04.html | 412 ++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 libstdc++-v3/doc/html/manual/bk01pt03ch17s04.html (limited to 'libstdc++-v3/doc/html/manual/bk01pt03ch17s04.html') diff --git a/libstdc++-v3/doc/html/manual/bk01pt03ch17s04.html b/libstdc++-v3/doc/html/manual/bk01pt03ch17s04.html new file mode 100644 index 000000000..3e35af0fa --- /dev/null +++ b/libstdc++-v3/doc/html/manual/bk01pt03ch17s04.html @@ -0,0 +1,412 @@ + + +Design

+

+

The 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:

+

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.

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 = 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 bug hunting 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 (since incorporated into the C++0x language specification, described in the GCC Manual for the C++ language as + namespace + association), and a 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. The release mode version is defined within the + namespace std. Minus the namespace associations, this + method leaves the behavior of release mode completely unchanged from + its behavior prior to the introduction of the libstdc++ debug + mode. Here's an example of what this ends up looking like, in + C++.

+namespace std
+{
+  template<typename _Tp, typename _Alloc = allocator<_Tp> >
+    class list
+    {
+      // ...
+     };
+} // namespace std
+

In debug mode we include the release-mode container (which is now +defined in the namespace __cxx1998) and also the +debug-mode container. The debug-mode container is defined within the +namespace __debug, which is associated with namespace +std via the C++0x namespace association language feature. This +method allows the debug and release versions of the same component to +coexist at compile-time and link-time without causing an unreasonable +maintenance burden, while minimizing confusion. Again, this boils down +to C++ code as follows:

+namespace std
+{
+  namespace __cxx1998
+  {
+    template<typename _Tp, typename _Alloc = allocator<_Tp> >
+      class list
+      {
+	// ...
+      };
+  } // namespace __gnu_norm
+
+  namespace __debug
+  {
+    template<typename _Tp, typename _Alloc = allocator<_Tp> >
+      class list
+      : public __cxx1998::list<_Tp, _Alloc>,
+	public __gnu_debug::_Safe_sequence<list<_Tp, _Alloc> >
+      {
+	// ...
+      };
+  } // namespace __cxx1998
+
+  // namespace __debug __attribute__ ((strong));
+  inline namespace __debug { }
+}
+

Because each component has a distinct and separate release and +debug implementation, there is no issue with link-time +coexistence: the separate namespaces result in different mangled +names, and thus unique linkage.

However, components that are defined and used within the C++ +standard library itself face additional constraints. For instance, +some of the member functions of std::moneypunct return +std::basic_string. Normally, this is not a problem, but +with a mixed mode standard library that could be using either +debug-mode or release-mode basic_string objects, things +get more complicated. As the return value of a function is not +encoded into the mangled name, there is no way to specify a +release-mode or a debug-mode string. In practice, this results in +runtime errors. A simplified example of this problem is as follows. +

Take this translation unit, compiled in debug-mode:

+// -D_GLIBCXX_DEBUG
+#include <string>
+
+std::string test02();
+
+std::string test01()
+{
+  return test02();
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
+

... and linked to this translation unit, compiled in release mode:

+#include <string>
+
+std::string
+test02()
+{
+  return std::string("toast");
+}
+

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 above 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.

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.

+

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:

  • SafeSTL: + SafeSTL was the original debugging version of the Standard Template + Library (STL), implemented by Cay S. Horstmann on top of the + Hewlett-Packard STL. Though it inspired much work in this area, it + has not been kept up-to-date for use with modern compilers or C++ + standard library implementations.

  • STLport: STLport is a free + implementation of the C++ standard library derived from the SGI implementation, and + ported to many other platforms. It includes a debug mode that uses a + wrapper model (that in some ways inspired the libstdc++ debug mode + design), although at the time of this writing the debug mode is + somewhat incomplete and meets only the "Full user recompilation" (2) + recompilation guarantee by requiring the user to link against a + different library in debug mode vs. release mode.

  • Metrowerks CodeWarrior: The C++ standard library + that ships with Metrowerks CodeWarrior includes a debug mode. It is + a full debug-mode implementation (including debugging for + CodeWarrior extensions) and is easy to use, although it meets only + the "Full recompilation" (1) recompilation + guarantee.

-- cgit v1.2.3