diff mbox

vector lightweight debug mode

Message ID 55F9C4F6.6030706@gmail.com
State New
Headers show

Commit Message

François Dumont Sept. 16, 2015, 7:37 p.m. UTC
On 14/09/2015 21:50, Jonathan Wakely wrote:
> On 14/09/15 20:27 +0200, François Dumont wrote:
>> Hi
>>
>>    Here is what I had in mind when talking about moving debug checks to
>> the lightweight debug checks.
>
> Ah yes, I hadn't thought about removing reundant checks from the
> __gnu_debug containers, but that makes sense.
>
>>    Sometimes the checks have been simply moved resulting in a simpler
>> debug vector implementation (front, back...). Sometimes I copy the
>> checks in a simpler form and kept the debug one too to make sure
>> execution of the debug code is fine.
>>
>>    I plan to do the same for other containers.
>>
>>    I still need to run tests, ok if tests are fine ?
>>
>> François
>>
>
>> diff --git a/libstdc++-v3/include/bits/stl_vector.h
>> b/libstdc++-v3/include/bits/stl_vector.h
>> index 305d446..89a9aec 100644
>> --- a/libstdc++-v3/include/bits/stl_vector.h
>> +++ b/libstdc++-v3/include/bits/stl_vector.h
>> @@ -449,6 +449,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>       vector&
>>       operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
>>       {
>> +    __glibcxx_assert(this != &__x);
>
> Please don't do this, it fails in valid programs. The standard needs
> to be fixed in this regard.

The debug mode check should be removed too then.

>
>>         constexpr bool __move_storage =
>>           _Alloc_traits::_S_propagate_on_move_assign()
>>           || _Alloc_traits::_S_always_equal();
>> @@ -778,7 +779,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>        */
>>       reference
>>       operator[](size_type __n) _GLIBCXX_NOEXCEPT
>> -      { return *(this->_M_impl._M_start + __n); }
>> +      {
>> +    __glibcxx_assert(__n < size());
>> +    return *(this->_M_impl._M_start + __n);
>> +      }
>
> This could use __glibcxx_requires_subscript(__n), see the attached
> patch.

    I thought you didn't want to use anything from debug.h so I try to
do with only __glibcxx_assert coming from c++config. I think your patch
is missing include of debug.h.

    But I was going to propose to use _Error_formatter also in this
mode, I do not see any reason to not do so. The attached patch does just
that.

>
>>
>>       /**
>>        *  @brief  Subscript access to the data contained in the %vector.
>> @@ -793,7 +797,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>        */
>>       const_reference
>>       operator[](size_type __n) const _GLIBCXX_NOEXCEPT
>> -      { return *(this->_M_impl._M_start + __n); }
>> +      {
>> +    __glibcxx_assert(__n < size());
>> +    return *(this->_M_impl._M_start + __n);
>> +      }
>>
>>     protected:
>>       /// Safety check used only from at().
>> @@ -850,7 +857,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>        */
>>       reference
>>       front() _GLIBCXX_NOEXCEPT
>> -      { return *begin(); }
>> +      {
>> +    __glibcxx_assert(!empty());
>
> This is __glibcxx_requires_nonempty(), already defined for
> _GLIBCXX_ASSERTIONS.
>
>> @@ -1051,6 +1071,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>       iterator
>>       insert(const_iterator __position, size_type __n, const
>> value_type& __x)
>>       {
>> +    __glibcxx_assert(__position >= cbegin() && __position <= cend());
>>     difference_type __offset = __position - cbegin();
>>     _M_fill_insert(begin() + __offset, __n, __x);
>>     return begin() + __offset;
>
> This is undefined behaviour, so I'd rather not add this check (I know
> it's on the google branch, but it's still undefined behaviour).

Why ? Because of the >= operator usage ? Is the attached patch better ?
< and == operators are well defined for a random access iterator, no ?

>
> We could do it with std::less, I suppose.
>
> I've attached the simplest checks I thought we should add for vector
> and deque.
>
>

Comments

Jonathan Wakely Sept. 16, 2015, 8:29 p.m. UTC | #1
On 16/09/15 21:37 +0200, François Dumont wrote:
>On 14/09/2015 21:50, Jonathan Wakely wrote:
>> On 14/09/15 20:27 +0200, François Dumont wrote:
>>> diff --git a/libstdc++-v3/include/bits/stl_vector.h
>>> b/libstdc++-v3/include/bits/stl_vector.h
>>> index 305d446..89a9aec 100644
>>> --- a/libstdc++-v3/include/bits/stl_vector.h
>>> +++ b/libstdc++-v3/include/bits/stl_vector.h
>>> @@ -449,6 +449,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>>       vector&
>>>       operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
>>>       {
>>> +    __glibcxx_assert(this != &__x);
>>
>> Please don't do this, it fails in valid programs. The standard needs
>> to be fixed in this regard.
>
>The debug mode check should be removed too then.

Yes.


>>
>>>         constexpr bool __move_storage =
>>>           _Alloc_traits::_S_propagate_on_move_assign()
>>>           || _Alloc_traits::_S_always_equal();
>>> @@ -778,7 +779,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>>        */
>>>       reference
>>>       operator[](size_type __n) _GLIBCXX_NOEXCEPT
>>> -      { return *(this->_M_impl._M_start + __n); }
>>> +      {
>>> +    __glibcxx_assert(__n < size());
>>> +    return *(this->_M_impl._M_start + __n);
>>> +      }
>>
>> This could use __glibcxx_requires_subscript(__n), see the attached
>> patch.
>
>    I thought you didn't want to use anything from debug.h so I try to
>do with only __glibcxx_assert coming from c++config. I think your patch
>is missing include of debug.h.
>
>    But I was going to propose to use _Error_formatter also in this
>mode, I do not see any reason to not do so. The attached patch does just
>that.

That pulls in extra dependencies on I/O and fprintf and things, which
can cause code size to increase. Is it really worth it?


>>> @@ -1051,6 +1071,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>>       iterator
>>>       insert(const_iterator __position, size_type __n, const
>>> value_type& __x)
>>>       {
>>> +    __glibcxx_assert(__position >= cbegin() && __position <= cend());
>>>     difference_type __offset = __position - cbegin();
>>>     _M_fill_insert(begin() + __offset, __n, __x);
>>>     return begin() + __offset;
>>
>> This is undefined behaviour, so I'd rather not add this check (I know
>> it's on the google branch, but it's still undefined behaviour).
>
>Why ? Because of the >= operator usage ? Is the attached patch better ?
>< and == operators are well defined for a random access iterator, no ?

No, because it is undefined to compare iterators that belong to
different containers, or to compare pointers that point to different
arrays.
Christopher Jefferson Sept. 17, 2015, 8:52 p.m. UTC | #2
---------- Forwarded message ----------
From: Christopher Jefferson <chris@bubblescope.net>
Date: 17 September 2015 at 18:59
Subject: Re: vector lightweight debug mode
To: Jonathan Wakely <jwakely@redhat.com>


On 16 September 2015 at 21:29, Jonathan Wakely <jwakely@redhat.com> wrote:
> On 16/09/15 21:37 +0200, François Dumont wrote:
>
>>>> @@ -1051,6 +1071,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>>>       iterator
>>>>       insert(const_iterator __position, size_type __n, const
>>>> value_type& __x)
>>>>       {
>>>> +    __glibcxx_assert(__position >= cbegin() && __position <= cend());
>>>>     difference_type __offset = __position - cbegin();
>>>>     _M_fill_insert(begin() + __offset, __n, __x);
>>>>     return begin() + __offset;
>>>
>>>
>>> This is undefined behaviour, so I'd rather not add this check (I know
>>> it's on the google branch, but it's still undefined behaviour).
>>
>>
>> Why ? Because of the >= operator usage ? Is the attached patch better ?
>> < and == operators are well defined for a random access iterator, no ?
>
>
> No, because it is undefined to compare iterators that belong to
> different containers, or to compare pointers that point to different
> arrays.

While that's true, on the other hand it's defined behaviour when the
assert passes, and in the case where the thing it's trying to check
fails, we are off into undefined-land anyway.

A defined check would be to check if __offset is < 0 or > size(). Once
again if it's false we are undefined, but the assert line itself is
then defined behaviour.
François Dumont Sept. 19, 2015, 7:31 a.m. UTC | #3
On 16/09/2015 22:29, Jonathan Wakely wrote:
>
>>>
>>>>         constexpr bool __move_storage =
>>>>           _Alloc_traits::_S_propagate_on_move_assign()
>>>>           || _Alloc_traits::_S_always_equal();
>>>> @@ -778,7 +779,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>>>        */
>>>>       reference
>>>>       operator[](size_type __n) _GLIBCXX_NOEXCEPT
>>>> -      { return *(this->_M_impl._M_start + __n); }
>>>> +      {
>>>> +    __glibcxx_assert(__n < size());
>>>> +    return *(this->_M_impl._M_start + __n);
>>>> +      }
>>>
>>> This could use __glibcxx_requires_subscript(__n), see the attached
>>> patch.
>>
>>    I thought you didn't want to use anything from debug.h so I try to
>> do with only __glibcxx_assert coming from c++config. I think your patch
>> is missing include of debug.h.
>>
>>    But I was going to propose to use _Error_formatter also in this
>> mode, I do not see any reason to not do so. The attached patch does just
>> that.
>
> That pulls in extra dependencies on I/O and fprintf and things, which
> can cause code size to increase. Is it really worth it?

Not that much dependencies. We only need formatters.h in this mode which
has the following common includes:

#include <bits/c++config.h>
#include <bits/cpp_type_traits.h>

and if rtti is enabled the less common:

#include <typeinfo>

We would just leverage on the good job done to diagnose problems.

>
>
>>>> @@ -1051,6 +1071,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>>>       iterator
>>>>       insert(const_iterator __position, size_type __n, const
>>>> value_type& __x)
>>>>       {
>>>> +    __glibcxx_assert(__position >= cbegin() && __position <= cend());
>>>>     difference_type __offset = __position - cbegin();
>>>>     _M_fill_insert(begin() + __offset, __n, __x);
>>>>     return begin() + __offset;
>>>
>>> This is undefined behaviour, so I'd rather not add this check (I know
>>> it's on the google branch, but it's still undefined behaviour).
>>
>> Why ? Because of the >= operator usage ? Is the attached patch better ?
>> < and == operators are well defined for a random access iterator, no ?
>
> No, because it is undefined to compare iterators that belong to
> different containers, or to compare pointers that point to different
> arrays.
>

(Written before Christopher reply:)

At least program will compile only if iterator is coming from a vector
of the same type. So behavior is undefined only if user pass an invalid
iterator which is exactly what this check tries to detect, isn't it
paradoxical ? If this undefined behavior results in the program abortion
this is what should happen anyway. If it doesn't abort then the program
will definitely not behaves as expected so this check doesn't make
anything worst, no ?

François
Jonathan Wakely Sept. 19, 2015, 9:08 a.m. UTC | #4
On 17 September 2015 at 21:52, Christopher Jefferson
<chris@bubblescope.net> wrote:
> ---------- Forwarded message ----------
> From: Christopher Jefferson <chris@bubblescope.net>
> Date: 17 September 2015 at 18:59
> Subject: Re: vector lightweight debug mode
> To: Jonathan Wakely <jwakely@redhat.com>
>
>
> On 16 September 2015 at 21:29, Jonathan Wakely <jwakely@redhat.com> wrote:
>> On 16/09/15 21:37 +0200, François Dumont wrote:
>>
>>>>> @@ -1051,6 +1071,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>>>>       iterator
>>>>>       insert(const_iterator __position, size_type __n, const
>>>>> value_type& __x)
>>>>>       {
>>>>> +    __glibcxx_assert(__position >= cbegin() && __position <= cend());
>>>>>     difference_type __offset = __position - cbegin();
>>>>>     _M_fill_insert(begin() + __offset, __n, __x);
>>>>>     return begin() + __offset;
>>>>
>>>>
>>>> This is undefined behaviour, so I'd rather not add this check (I know
>>>> it's on the google branch, but it's still undefined behaviour).
>>>
>>>
>>> Why ? Because of the >= operator usage ? Is the attached patch better ?
>>> < and == operators are well defined for a random access iterator, no ?
>>
>>
>> No, because it is undefined to compare iterators that belong to
>> different containers, or to compare pointers that point to different
>> arrays.
>
> While that's true, on the other hand it's defined behaviour when the
> assert passes, and in the case where the thing it's trying to check
> fails, we are off into undefined-land anyway.
>
> A defined check would be to check if __offset is < 0 or > size(). Once
> again if it's false we are undefined, but the assert line itself is
> then defined behaviour.

That's a good point, but it still means an optimiser could remove the
checks, because it is impossible for them to fail in a correct
program.

That would be no worse than not having the checks at all, but it could
make them unreliable.
Jonathan Wakely Sept. 19, 2015, 9:12 a.m. UTC | #5
On 19 September 2015 at 08:31, François Dumont wrote:
> On 16/09/2015 22:29, Jonathan Wakely wrote:
>> No, because it is undefined to compare iterators that belong to
>> different containers, or to compare pointers that point to different
>> arrays.
>>
>
> (Written before Christopher reply:)
>
> At least program will compile only if iterator is coming from a vector
> of the same type. So behavior is undefined only if user pass an invalid
> iterator which is exactly what this check tries to detect, isn't it
> paradoxical ? If this undefined behavior results in the program abortion
> this is what should happen anyway. If it doesn't abort then the program
> will definitely not behaves as expected so this check doesn't make
> anything worst, no ?

The problem is that undefined behaviour can "travel backwards in time".

It's not as simple as saying that if the invalid check happens _then_
undefined behaviour happens afterwards.

However, Google seem to find these checks useful, and you and Chris
are in favour, so let's keep them.
Jonathan Wakely Sept. 19, 2015, 9:47 a.m. UTC | #6
On 19 September 2015 at 10:12, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> On 19 September 2015 at 08:31, François Dumont wrote:
>> On 16/09/2015 22:29, Jonathan Wakely wrote:
>>> No, because it is undefined to compare iterators that belong to
>>> different containers, or to compare pointers that point to different
>>> arrays.
>>>
>>
>> (Written before Christopher reply:)
>>
>> At least program will compile only if iterator is coming from a vector
>> of the same type. So behavior is undefined only if user pass an invalid
>> iterator which is exactly what this check tries to detect, isn't it
>> paradoxical ? If this undefined behavior results in the program abortion
>> this is what should happen anyway. If it doesn't abort then the program
>> will definitely not behaves as expected so this check doesn't make
>> anything worst, no ?
>
> The problem is that undefined behaviour can "travel backwards in time".
>
> It's not as simple as saying that if the invalid check happens _then_
> undefined behaviour happens afterwards.

Just to be clear, I agree that it can't hurt a correct program (except
for the small cost of doing the checks).

My concern was that for an incorrect program (which is the entire
purpose of adding the checks) the results could be unpredictable. It
might abort, which is the desired behaviour, or it might do something
else and keep executing, and in that case it could be harmful for
debugging because users would look at the source and think "well my
iterators must be in range, otherwise that assertion would have
failed, so the bug must be elsewhere".

However ...

> However, Google seem to find these checks useful, and you and Chris
> are in favour, so let's keep them.
diff mbox

Patch

diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index 305d446..b84e653 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -63,6 +63,8 @@ 
 #include <initializer_list>
 #endif
 
+#include <debug/debug.h>
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
@@ -778,7 +780,10 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       reference
       operator[](size_type __n) _GLIBCXX_NOEXCEPT
-      { return *(this->_M_impl._M_start + __n); }
+      {
+	__glibcxx_requires_subscript(__n);
+	return *(this->_M_impl._M_start + __n);
+      }
 
       /**
        *  @brief  Subscript access to the data contained in the %vector.
@@ -793,7 +798,10 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       const_reference
       operator[](size_type __n) const _GLIBCXX_NOEXCEPT
-      { return *(this->_M_impl._M_start + __n); }
+      {
+	__glibcxx_requires_subscript(__n);
+	return *(this->_M_impl._M_start + __n);
+      }
 
     protected:
       /// Safety check used only from at().
@@ -850,7 +858,10 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       reference
       front() _GLIBCXX_NOEXCEPT
-      { return *begin(); }
+      {
+	__glibcxx_requires_nonempty();
+	return *begin();
+      }
 
       /**
        *  Returns a read-only (constant) reference to the data at the first
@@ -858,7 +869,10 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       const_reference
       front() const _GLIBCXX_NOEXCEPT
-      { return *begin(); }
+      {
+	__glibcxx_requires_nonempty();
+	return *begin();
+      }
 
       /**
        *  Returns a read/write reference to the data at the last
@@ -866,7 +880,10 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       reference
       back() _GLIBCXX_NOEXCEPT
-      { return *(end() - 1); }
+      {
+	__glibcxx_requires_nonempty();
+	return *(end() - 1);
+      }
       
       /**
        *  Returns a read-only (constant) reference to the data at the
@@ -874,7 +891,10 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       const_reference
       back() const _GLIBCXX_NOEXCEPT
-      { return *(end() - 1); }
+      {
+	__glibcxx_requires_nonempty();
+	return *(end() - 1);
+      }
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 464. Suggestion for new member functions in standard containers.
@@ -949,6 +969,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       void
       pop_back() _GLIBCXX_NOEXCEPT
       {
+	__glibcxx_requires_nonempty();
 	--this->_M_impl._M_finish;
 	_Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
       }
@@ -1051,6 +1072,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       iterator
       insert(const_iterator __position, size_type __n, const value_type& __x)
       {
+	__glibcxx_assert((cbegin() < __position || !(__position < cbegin()))
+			 && (__position < cend() || !(cend() < __position)));
 	difference_type __offset = __position - cbegin();
 	_M_fill_insert(begin() + __offset, __n, __x);
 	return begin() + __offset;
@@ -1071,7 +1094,11 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       void
       insert(iterator __position, size_type __n, const value_type& __x)
-      { _M_fill_insert(__position, __n, __x); }
+      {
+	__glibcxx_assert((begin() < __position || !(__position < begin()))
+			 && (__position < end() || !(end() < __position)));
+	_M_fill_insert(__position, __n, __x);
+      }
 #endif
 
 #if __cplusplus >= 201103L
@@ -1096,6 +1123,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
         insert(const_iterator __position, _InputIterator __first,
 	       _InputIterator __last)
         {
+	  __glibcxx_assert((cbegin() < __position || !(__position < cbegin()))
+			   && (__position < cend() || !(cend() < __position)));
 	  difference_type __offset = __position - cbegin();
 	  _M_insert_dispatch(begin() + __offset,
 			     __first, __last, __false_type());
@@ -1121,6 +1150,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
         insert(iterator __position, _InputIterator __first,
 	       _InputIterator __last)
         {
+	  __glibcxx_assert((begin() < __position || !(__position < begin()))
+			   && (__position < end() || !(end() < __position)));
 	  // Check whether it's an integral type.  If so, it's not an iterator.
 	  typedef typename std::__is_integer<_InputIterator>::__type _Integral;
 	  _M_insert_dispatch(__position, __first, __last, _Integral());
@@ -1145,10 +1176,18 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       iterator
 #if __cplusplus >= 201103L
       erase(const_iterator __position)
-      { return _M_erase(begin() + (__position - cbegin())); }
+      {
+	__glibcxx_assert((cbegin() < __position || !(__position < cbegin()))
+			 && __position < cend());
+	return _M_erase(begin() + (__position - cbegin()));
+      }
 #else
       erase(iterator __position)
-      { return _M_erase(__position); }
+      {
+	__glibcxx_assert((begin() < __position || !(__position < begin()))
+			 && __position < end());
+	return _M_erase(__position);
+      }
 #endif
 
       /**
@@ -1173,13 +1212,25 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #if __cplusplus >= 201103L
       erase(const_iterator __first, const_iterator __last)
       {
+	__glibcxx_assert(__first < __last || !(__last < __first));
+	__glibcxx_assert((cbegin() < __first || !(__first < cbegin()))
+			 && (__first < cend() || __first == __last));
+	__glibcxx_assert((cbegin() < __last || __first == __last)
+			 && (__last < cend() || !(cend() < __last)));
 	const auto __beg = begin();
 	const auto __cbeg = cbegin();
 	return _M_erase(__beg + (__first - __cbeg), __beg + (__last - __cbeg));
       }
 #else
       erase(iterator __first, iterator __last)
-      { return _M_erase(__first, __last); }
+      {
+	__glibcxx_assert(__first < __last || !(__last < __first));
+	__glibcxx_assert((begin() < __first || !(__first < begin()))
+			 && (__first < end() || __first == __last));
+	__glibcxx_assert((begin() < __last || __first == __last)
+			 && (__last < end() || !(end() < __last)));
+	return _M_erase(__first, __last);
+      }
 #endif
 
       /**
@@ -1194,6 +1245,10 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       void
       swap(vector& __x) _GLIBCXX_NOEXCEPT
       {
+#if __cplusplus >= 201103L
+	__glibcxx_assert(_Alloc_traits::propagate_on_container_swap::value
+			 || _M_get_Tp_allocator() == __x._M_get_Tp_allocator());
+#endif
 	this->_M_impl._M_swap_data(__x._M_impl);
 	_Alloc_traits::_S_on_swap(_M_get_Tp_allocator(),
 	                          __x._M_get_Tp_allocator());
diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc
index 34118a4..b00a620 100644
--- a/libstdc++-v3/include/bits/vector.tcc
+++ b/libstdc++-v3/include/bits/vector.tcc
@@ -107,10 +107,15 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     vector<_Tp, _Alloc>::
 #if __cplusplus >= 201103L
     insert(const_iterator __position, const value_type& __x)
+    {
+      __glibcxx_assert((cbegin() < __position || !(__position < cbegin()))
+		       && (__position < cend() || !(cend() < __position)));
 #else
     insert(iterator __position, const value_type& __x)
-#endif
     {
+      __glibcxx_assert((begin() < __position || !(__position < begin()))
+		       && (__position < end() || !(end() < __position)));
+#endif
       const size_type __n = __position - begin();
       if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage
 	  && __position == end())
@@ -301,6 +306,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       vector<_Tp, _Alloc>::
       emplace(const_iterator __position, _Args&&... __args)
       {
+	__glibcxx_assert((cbegin() < __position || !(__position < cbegin()))
+			 && (__position < cend() || !(cend() < __position)));
 	const size_type __n = __position - begin();
 	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage
 	    && __position == end())
diff --git a/libstdc++-v3/include/debug/debug.h b/libstdc++-v3/include/debug/debug.h
index b5935fe..ea9c0c2 100644
--- a/libstdc++-v3/include/debug/debug.h
+++ b/libstdc++-v3/include/debug/debug.h
@@ -74,68 +74,66 @@  namespace __gnu_debug
 # define __glibcxx_requires_heap_pred(_First,_Last,_Pred)
 # define __glibcxx_requires_string(_String)
 # define __glibcxx_requires_string_len(_String,_Len)
-# define __glibcxx_requires_subscript(_N)
 # define __glibcxx_requires_irreflexive(_First,_Last)
 # define __glibcxx_requires_irreflexive2(_First,_Last)
 # define __glibcxx_requires_irreflexive_pred(_First,_Last,_Pred)
 # define __glibcxx_requires_irreflexive_pred2(_First,_Last,_Pred)
 
-#ifdef _GLIBCXX_ASSERTIONS
-// Verify that [_First, _Last) forms a non-empty iterator range.
-# define __glibcxx_requires_non_empty_range(_First,_Last) \
-  __glibcxx_assert(_First != _Last)
-// Verify that the container is nonempty
-# define __glibcxx_requires_nonempty() \
-  __glibcxx_assert(! this->empty())
-#else
-# define __glibcxx_requires_non_empty_range(_First,_Last)
-# define __glibcxx_requires_nonempty()
 #endif
 
+#ifndef _GLIBCXX_ASSERTIONS
+# define __glibcxx_requires_non_empty_range(_First,_Last)
+# define __glibcxx_requires_nonempty()
+# define __glibcxx_requires_subscript(_N)
 #else
 
 # include <debug/macros.h>
 
-# define __glibcxx_requires_cond(_Cond,_Msg) _GLIBCXX_DEBUG_VERIFY(_Cond,_Msg)
-# define __glibcxx_requires_valid_range(_First,_Last)	\
+# ifdef _GLIBCXX_DEBUG
+#  define __glibcxx_requires_cond(_Cond,_Msg) _GLIBCXX_DEBUG_VERIFY(_Cond,_Msg)
+#  define __glibcxx_requires_valid_range(_First,_Last)	\
   __glibcxx_check_valid_range(_First,_Last)
-# define __glibcxx_requires_non_empty_range(_First,_Last)	\
-  __glibcxx_check_non_empty_range(_First,_Last)
-# define __glibcxx_requires_sorted(_First,_Last)	\
+#  define __glibcxx_requires_sorted(_First,_Last)	\
   __glibcxx_check_sorted(_First,_Last)
-# define __glibcxx_requires_sorted_pred(_First,_Last,_Pred)	\
+#  define __glibcxx_requires_sorted_pred(_First,_Last,_Pred)	\
   __glibcxx_check_sorted_pred(_First,_Last,_Pred)
-# define __glibcxx_requires_sorted_set(_First1,_Last1,_First2)	\
+#  define __glibcxx_requires_sorted_set(_First1,_Last1,_First2)	\
   __glibcxx_check_sorted_set(_First1,_Last1,_First2)
-# define __glibcxx_requires_sorted_set_pred(_First1,_Last1,_First2,_Pred) \
+#  define __glibcxx_requires_sorted_set_pred(_First1,_Last1,_First2,_Pred) \
   __glibcxx_check_sorted_set_pred(_First1,_Last1,_First2,_Pred)
-# define __glibcxx_requires_partitioned_lower(_First,_Last,_Value)	\
+#  define __glibcxx_requires_partitioned_lower(_First,_Last,_Value)	\
   __glibcxx_check_partitioned_lower(_First,_Last,_Value)
-# define __glibcxx_requires_partitioned_upper(_First,_Last,_Value)	\
+#  define __glibcxx_requires_partitioned_upper(_First,_Last,_Value)	\
   __glibcxx_check_partitioned_upper(_First,_Last,_Value)
-# define __glibcxx_requires_partitioned_lower_pred(_First,_Last,_Value,_Pred) \
+#  define __glibcxx_requires_partitioned_lower_pred(_First,_Last,_Value,_Pred) \
   __glibcxx_check_partitioned_lower_pred(_First,_Last,_Value,_Pred)
-# define __glibcxx_requires_partitioned_upper_pred(_First,_Last,_Value,_Pred) \
+#  define __glibcxx_requires_partitioned_upper_pred(_First,_Last,_Value,_Pred) \
   __glibcxx_check_partitioned_upper_pred(_First,_Last,_Value,_Pred)
-# define __glibcxx_requires_heap(_First,_Last)	\
+#  define __glibcxx_requires_heap(_First,_Last)	\
   __glibcxx_check_heap(_First,_Last)
-# define __glibcxx_requires_heap_pred(_First,_Last,_Pred)	\
+#  define __glibcxx_requires_heap_pred(_First,_Last,_Pred)	\
   __glibcxx_check_heap_pred(_First,_Last,_Pred)
-# define __glibcxx_requires_nonempty() __glibcxx_check_nonempty()
-# define __glibcxx_requires_string(_String) __glibcxx_check_string(_String)
-# define __glibcxx_requires_string_len(_String,_Len)	\
+#  define __glibcxx_requires_string(_String) __glibcxx_check_string(_String)
+#  define __glibcxx_requires_string_len(_String,_Len)	\
   __glibcxx_check_string_len(_String,_Len)
-# define __glibcxx_requires_subscript(_N) __glibcxx_check_subscript(_N)
-# define __glibcxx_requires_irreflexive(_First,_Last)	\
+#  define __glibcxx_requires_irreflexive(_First,_Last)	\
   __glibcxx_check_irreflexive(_First,_Last)
-# define __glibcxx_requires_irreflexive2(_First,_Last)	\
+#  define __glibcxx_requires_irreflexive2(_First,_Last)	\
   __glibcxx_check_irreflexive2(_First,_Last)
-# define __glibcxx_requires_irreflexive_pred(_First,_Last,_Pred)	\
+#  define __glibcxx_requires_irreflexive_pred(_First,_Last,_Pred)	\
   __glibcxx_check_irreflexive_pred(_First,_Last,_Pred)
-# define __glibcxx_requires_irreflexive_pred2(_First,_Last,_Pred)	\
+#  define __glibcxx_requires_irreflexive_pred2(_First,_Last,_Pred)	\
   __glibcxx_check_irreflexive_pred2(_First,_Last,_Pred)
 
-# include <debug/functions.h>
+#  include <debug/functions.h>
+#endif
+
+# define __glibcxx_requires_subscript(_N) __glibcxx_check_subscript(_N)
+# define __glibcxx_requires_non_empty_range(_First,_Last)	\
+  __glibcxx_check_non_empty_range(_First,_Last)
+# define __glibcxx_requires_nonempty() __glibcxx_check_nonempty()
+
+# include <debug/formatter.h>
 
 #endif
 
diff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector
index fede4f0..7fccf28 100644
--- a/libstdc++-v3/include/debug/vector
+++ b/libstdc++-v3/include/debug/vector
@@ -406,49 +406,10 @@  namespace __debug
       }
 
       // element access:
-      reference
-      operator[](size_type __n) _GLIBCXX_NOEXCEPT
-      {
-	__glibcxx_check_subscript(__n);
-	return _M_base()[__n];
-      }
-
-      const_reference
-      operator[](size_type __n) const _GLIBCXX_NOEXCEPT
-      {
-	__glibcxx_check_subscript(__n);
-	return _M_base()[__n];
-      }
-
+      using _Base::operator[];
       using _Base::at;
-
-      reference
-      front() _GLIBCXX_NOEXCEPT
-      {
-	__glibcxx_check_nonempty();
-	return _Base::front();
-      }
-
-      const_reference
-      front() const _GLIBCXX_NOEXCEPT
-      {
-	__glibcxx_check_nonempty();
-	return _Base::front();
-      }
-
-      reference
-      back() _GLIBCXX_NOEXCEPT
-      {
-	__glibcxx_check_nonempty();
-	return _Base::back();
-      }
-
-      const_reference
-      back() const _GLIBCXX_NOEXCEPT
-      {
-	__glibcxx_check_nonempty();
-	return _Base::back();
-      }
+      using _Base::front;
+      using _Base::back;
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 464. Suggestion for new member functions in standard containers.