Patchwork Make vector::at() assertion message more useful (try #2)

login
register
mail settings
Submitter Paul Pluzhnikov
Date Sept. 18, 2013, 7:38 p.m.
Message ID <CALoOobMejGJLVVCszP8Joa+4B21UbvK4chyFUnjiCNPP0GJF0A@mail.gmail.com>
Download mbox | patch
Permalink /patch/275787/
State New
Headers show

Comments

Paul Pluzhnikov - Sept. 18, 2013, 7:38 p.m.
On Fri, Sep 13, 2013 at 3:02 AM, Paolo Carlini <paolo.carlini@oracle.com> wrote:

> - The game with the variadic and the non-variadic __throw_out_of_range makes
> me a little nervous. Let's just name the new one differently, like
> __throw_out_of_range_var.

Replaced with __throw_out_of_range_fmt.

> - Please consistently use __builtin_alloca everywhere, alloca isn't a
> standard function.

Done.

> - I would rather call the file itself snprintf_lite.cc, in order not to fool
> somebody that it actually implements the whole snprintf.

Done.

> - I'm a bit confused about __concat_size_t returning -1. Since it only
> formats integers, I think we can be *sure* that the buffer is big enough.

How so? The caller could do this:

  __snprintf_lite("aaa: %zu, 8, 12345678);

By the time we get to __concat_size_t, we only have 3 characters left.

> Then, if it returns -1 something is going *very badly* wrong, shouldn't we
> __builtin_abort() or something similar?

I've re-worked this part -- if this ever happens, throw a logic_error with
a message to file a bug.

> - In terms of buffer sizes, this comment:
>
>     // enough for expanding up to 5 size_t's in the format.
>
> and then the actual code in __snprintf_lite makes me a little nervous.
> Agreed, we are not going to overflow the buffer, but truncating with no
> diagnostic whatsoever seems rather gross. We can probably sort out this
> later, new ideas welcome, anyway.

Re-worked.

> - While we are at it, shouldn't we use the new facility at least in array,
> vector<bool> and deque too? For consistency over the containers.

Done.

I also expanded snprintf_lite to handle '%s', as that comes handy inside
string _M_check.

Thanks,

P.S. In the process of updating callers of __throw_out_of_range, I've
discovered that two of them had already used __builtin_sprintf.

P.P.S. Sorry this patch grew ... I can split it into parts if that's easier
to review.
Paolo Carlini - Sept. 18, 2013, 10 p.m.
Hi,

> Il giorno 18/set/2013, alle ore 21:38, Paul Pluzhnikov <ppluzhnikov@google.com> ha scritto:
> 
>> On Fri, Sep 13, 2013 at 3:02 AM, Paolo Carlini <paolo.carlini@oracle.com> wrote:
>> 
>> - The game with the variadic and the non-variadic __throw_out_of_range makes
>> me a little nervous. Let's just name the new one differently, like
>> __throw_out_of_range_var.
> 
> Replaced with __throw_out_of_range_fmt.
> 
>> - Please consistently use __builtin_alloca everywhere, alloca isn't a
>> standard function.
> 
> Done.
> 
>> - I would rather call the file itself snprintf_lite.cc, in order not to fool
>> somebody that it actually implements the whole snprintf.
> 
> Done.
> 
>> - I'm a bit confused about __concat_size_t returning -1. Since it only
>> formats integers, I think we can be *sure* that the buffer is big enough.
> 
> How so? The caller could do this:
> 
>  __snprintf_lite("aaa: %zu, 8, 12345678);
> 
> By the time we get to __concat_size_t, we only have 3 characters left.

Ok, thanks, I think I misread the code. In general I meant that you can bound a priori the number of chars you need to format an integer - that isn't the case for floats, for example (the user may want a ridiculously large number of decimal digits). But you are in fact already exploiting that for the value of __ilen.

> 
>> Then, if it returns -1 something is going *very badly* wrong, shouldn't we
>> __builtin_abort() or something similar?
> 
> I've re-worked this part -- if this ever happens, throw a logic_error with
> a message to file a bug.
> 
>> - In terms of buffer sizes, this comment:
>> 
>>    // enough for expanding up to 5 size_t's in the format.
>> 
>> and then the actual code in __snprintf_lite makes me a little nervous.
>> Agreed, we are not going to overflow the buffer, but truncating with no
>> diagnostic whatsoever seems rather gross. We can probably sort out this
>> later, new ideas welcome, anyway.
> 
> Re-worked.
> 
>> - While we are at it, shouldn't we use the new facility at least in array,
>> vector<bool> and deque too? For consistency over the containers.
> 
> Done.
> 
> I also expanded snprintf_lite to handle '%s', as that comes handy inside
> string _M_check.
> 
> Thanks,
> 
> P.S. In the process of updating callers of __throw_out_of_range, I've
> discovered that two of them had already used __builtin_sprintf.
> 
> P.P.S. Sorry this patch grew ... I can split it into parts if that's easier
> to review.

In general I like this version of the patch a lot. Thus assuming nobody else has further comments over the next day or so, please commit it at your ease. In the meanwhile, since you are also touching debug-mode and profile-mode, make sure to run check-debug and check-profile too.


Thanks,
Paolo
Paul Pluzhnikov - Sept. 22, 2013, 2:08 a.m.
On Wed, Sep 18, 2013 at 3:00 PM, Paolo Carlini <paolo.carlini@oracle.com> wrote:

> In the meanwhile, since you are also touching debug-mode and
> profile-mode, make sure to run check-debug and check-profile too.

Thanks for mentioning that. Several more tests needed line number
adjustments.

There are also tests that are failing there independently of my patch.

Committed as r202818.

Thanks,
Andreas Schwab - Sept. 23, 2013, 8:53 a.m.
Paul Pluzhnikov <ppluzhnikov@google.com> writes:

> Index: libstdc++-v3/src/c++11/snprintf_lite.cc
> ===================================================================
> --- libstdc++-v3/src/c++11/snprintf_lite.cc	(revision 0)
> +++ libstdc++-v3/src/c++11/snprintf_lite.cc	(revision 0)
> @@ -0,0 +1,152 @@
> +// Debugging support -*- C++ -*-
> +
> +// Copyright (C) 2013 Free Software Foundation, Inc.
> +//
> +// This file is part of GCC.
> +//
> +// GCC is free software; you can redistribute it and/or modify
> +// it under the terms of the GNU General Public License as published by
> +// the Free Software Foundation; either version 3, or (at your option)
> +// any later version.
> +//
> +// GCC is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +// GNU General Public License for more details.
> +//
> +// Under Section 7 of GPL version 3, you are granted additional
> +// permissions described in the GCC Runtime Library Exception, version
> +// 3.1, as published by the Free Software Foundation.
> +
> +// You should have received a copy of the GNU General Public License and
> +// a copy of the GCC Runtime Library Exception along with this program;
> +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> +// <http://www.gnu.org/licenses/>.
> +
> +#include <stdarg.h>
> +#include <bits/functexcept.h>
> +#include <bits/locale_facets.h>
> +
> +namespace std {
> +  template<typename _CharT, typename _ValueT>
> +  int
> +  __int_to_char(_CharT* __bufend, _ValueT __v, const _CharT* __lit,
> +                ios_base::fmtflags __flags, bool __dec);
> +}
> +

m68k-linux/./libstdc++-v3/src/.libs/libstdc++.so: undefined reference to `int std::__int_to_char<char, unsigned int>(char*, unsigned int, char const*, std::_Ios_Fmtflags, bool)'

Andreas.
Paolo Carlini - Sept. 23, 2013, 11:26 a.m.
Hi,

thanks Andreas.

On 9/23/13 3:53 AM, Andreas Schwab wrote:
> Paul Pluzhnikov<ppluzhnikov@google.com>  writes:
>
>> Index: libstdc++-v3/src/c++11/snprintf_lite.cc
>> ===================================================================
>> --- libstdc++-v3/src/c++11/snprintf_lite.cc	(revision 0)
>> +++ libstdc++-v3/src/c++11/snprintf_lite.cc	(revision 0)
>> @@ -0,0 +1,152 @@
>> +// Debugging support -*- C++ -*-
>> +
>> +// Copyright (C) 2013 Free Software Foundation, Inc.
>> +//
>> +// This file is part of GCC.
>> +//
>> +// GCC is free software; you can redistribute it and/or modify
>> +// it under the terms of the GNU General Public License as published by
>> +// the Free Software Foundation; either version 3, or (at your option)
>> +// any later version.
>> +//
>> +// GCC is distributed in the hope that it will be useful,
>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +// GNU General Public License for more details.
>> +//
>> +// Under Section 7 of GPL version 3, you are granted additional
>> +// permissions described in the GCC Runtime Library Exception, version
>> +// 3.1, as published by the Free Software Foundation.
>> +
>> +// You should have received a copy of the GNU General Public License and
>> +// a copy of the GCC Runtime Library Exception along with this program;
>> +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>> +//<http://www.gnu.org/licenses/>.
>> +
>> +#include<stdarg.h>
>> +#include<bits/functexcept.h>
>> +#include<bits/locale_facets.h>
>> +
>> +namespace std {
>> +  template<typename _CharT, typename _ValueT>
>> +  int
>> +  __int_to_char(_CharT* __bufend, _ValueT __v, const _CharT* __lit,
>> +                ios_base::fmtflags __flags, bool __dec);
>> +}
>> +
> m68k-linux/./libstdc++-v3/src/.libs/libstdc++.so: undefined reference to `int std::__int_to_char<char, unsigned int>(char*, unsigned int, char const*, std::_Ios_Fmtflags, bool)'
Paul, the *.cc are built with implicit instantiations disabled and we 
are missing explicit instantiations of this function template. If I 
remember correctly, we normally instantiate it in locale-inst.cc only 
for unsigned long and unsigned long long as second template argument. 
Thus, I would say, either make sure to use only those two in the new 
code, or add explicit instantiations. I would rather prefer the former, 
for example casting __val to (unsigned long long) in __concat_size_t 
isn't particularly elegant (vs for example checking if size_t isn't 
either unsigned long neither unsigned long long and adding an explicit 
instantiation only in that case) but would work I think. In any case, if 
it works for Andreas he is also preapproved to commit this kind change 
to unbreak his target.

Paolo.
Richard Guenther - Sept. 23, 2013, 11:39 a.m.
On Mon, Sep 23, 2013 at 1:26 PM, Paolo Carlini <paolo.carlini@oracle.com> wrote:
> Hi,
>
> thanks Andreas.
>
>
> On 9/23/13 3:53 AM, Andreas Schwab wrote:
>>
>> Paul Pluzhnikov<ppluzhnikov@google.com>  writes:
>>
>>> Index: libstdc++-v3/src/c++11/snprintf_lite.cc
>>> ===================================================================
>>> --- libstdc++-v3/src/c++11/snprintf_lite.cc     (revision 0)
>>> +++ libstdc++-v3/src/c++11/snprintf_lite.cc     (revision 0)
>>> @@ -0,0 +1,152 @@
>>> +// Debugging support -*- C++ -*-
>>> +
>>> +// Copyright (C) 2013 Free Software Foundation, Inc.
>>> +//
>>> +// This file is part of GCC.
>>> +//
>>> +// GCC is free software; you can redistribute it and/or modify
>>> +// it under the terms of the GNU General Public License as published by
>>> +// the Free Software Foundation; either version 3, or (at your option)
>>> +// any later version.
>>> +//
>>> +// GCC is distributed in the hope that it will be useful,
>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> +// GNU General Public License for more details.
>>> +//
>>> +// Under Section 7 of GPL version 3, you are granted additional
>>> +// permissions described in the GCC Runtime Library Exception, version
>>> +// 3.1, as published by the Free Software Foundation.
>>> +
>>> +// You should have received a copy of the GNU General Public License and
>>> +// a copy of the GCC Runtime Library Exception along with this program;
>>> +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>>> +//<http://www.gnu.org/licenses/>.
>>> +
>>> +#include<stdarg.h>
>>> +#include<bits/functexcept.h>
>>> +#include<bits/locale_facets.h>
>>> +
>>> +namespace std {
>>> +  template<typename _CharT, typename _ValueT>
>>> +  int
>>> +  __int_to_char(_CharT* __bufend, _ValueT __v, const _CharT* __lit,
>>> +                ios_base::fmtflags __flags, bool __dec);
>>> +}
>>> +
>>
>> m68k-linux/./libstdc++-v3/src/.libs/libstdc++.so: undefined reference to
>> `int std::__int_to_char<char, unsigned int>(char*, unsigned int, char
>> const*, std::_Ios_Fmtflags, bool)'
>
> Paul, the *.cc are built with implicit instantiations disabled and we are
> missing explicit instantiations of this function template. If I remember
> correctly, we normally instantiate it in locale-inst.cc only for unsigned
> long and unsigned long long as second template argument. Thus, I would say,
> either make sure to use only those two in the new code, or add explicit
> instantiations. I would rather prefer the former, for example casting __val
> to (unsigned long long) in __concat_size_t isn't particularly elegant (vs
> for example checking if size_t isn't either unsigned long neither unsigned
> long long and adding an explicit instantiation only in that case) but would
> work I think. In any case, if it works for Andreas he is also preapproved to
> commit this kind change to unbreak his target.

Btw, i?86 is broken as well (or -m32 testing on x86_64).

Richard.

> Paolo.
Andreas Schwab - Sept. 23, 2013, 11:45 a.m.
Paolo Carlini <paolo.carlini@oracle.com> writes:

> Paul, the *.cc are built with implicit instantiations disabled and we are
> missing explicit instantiations of this function template. If I remember
> correctly, we normally instantiate it in locale-inst.cc only for unsigned
> long and unsigned long long as second template argument. Thus, I would
> say, either make sure to use only those two in the new code, or add
> explicit instantiations. I would rather prefer the former, for example
> casting __val to (unsigned long long) in __concat_size_t isn't
> particularly elegant (vs for example checking if size_t isn't either
> unsigned long neither unsigned long long and adding an explicit
> instantiation only in that case)

What's wrong with always adding the instantiation?

> but would work I think. In any case, if it works for Andreas he is
> also preapproved to commit this kind change to unbreak his target.

There are a lot of targets using unsigned int for size_t, which would
have been uncovered by proper testing.

Andreas.
Paolo Carlini - Sept. 23, 2013, 1:14 p.m.
Hi

Andreas Schwab <schwab@suse.de> ha scritto:

>What's wrong with always adding the instantiation?

That quite a few targets will not use it and will remain dead in the .so? But I agree that it's an option, that you can also pursue immediately if you like, also preapproved (I'm traveling, either you or Paul or somebody else has to do the work, sorry)

>
>> but would work I think. In any case, if it works for Andreas he is
>> also preapproved to commit this kind change to unbreak his target.
>
>There are a lot of targets using unsigned int for size_t, which would
>have been uncovered by proper testing.

That's true, just remember to test *both* -m32 and -m64, for non trivial changes. How many times I have to repeat that?

Paolo
Andreas Schwab - Sept. 23, 2013, 1:22 p.m.
Paolo Carlini <paolo.carlini@oracle.com> writes:

> Hi
>
> Andreas Schwab <schwab@suse.de> ha scritto:
>
>>What's wrong with always adding the instantiation?
>
> That quite a few targets will not use it and will remain dead in the .so?

How many uses are there for the unsigned long version?

Andreas.
Marc Glisse - Sept. 23, 2013, 1:55 p.m.
On Mon, 23 Sep 2013, Paolo Carlini wrote:

>> There are a lot of targets using unsigned int for size_t, which would
>> have been uncovered by proper testing.

We can't test all patches on 3-4 different targets... It wasn't obvious 
this patch could be that sensitive to the target.

> That's true, just remember to test *both* -m32 and -m64, for non trivial 
> changes.

So how do you do that in practice ? Is it done by default if multilib is 
enabled? You also mentioned doing something special to check debug/profile 
modes recently, is there a make target to really perform all the tests 
necessary for a submission?

http://gcc.gnu.org/contribute.html has an outdated section on testing. It 
mentions that you should do a bootstrap for a change to the C front-end 
(should also be for the C++ front-end and I guess libstdc++ even if it 
isn't used much inside gcc).
Jakub Jelinek - Sept. 23, 2013, 2 p.m.
On Mon, Sep 23, 2013 at 03:55:26PM +0200, Marc Glisse wrote:
> On Mon, 23 Sep 2013, Paolo Carlini wrote:
> 
> >>There are a lot of targets using unsigned int for size_t, which would
> >>have been uncovered by proper testing.
> 
> We can't test all patches on 3-4 different targets... It wasn't
> obvious this patch could be that sensitive to the target.
> 
> >That's true, just remember to test *both* -m32 and -m64, for non
> >trivial changes.
> 
> So how do you do that in practice ? Is it done by default if
> multilib is enabled? You also mentioned doing something special to
> check debug/profile modes recently, is there a make target to really
> perform all the tests necessary for a submission?

It isn't done by default, but you can easily do that, by running
make check RUNTESTFLAGS='--target_board=unix\{-m32,-m64\}'
(either toplevel, or more specific, e.g. just in libstdc++-v3/
dir, or even
make check-gcc RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} dg.exp=pr12345.c'
etc.).
Or of course you can do two separate bootstraps/make check (that is what I'm usually
doing, so that both bootstraps are tested).
> 
> http://gcc.gnu.org/contribute.html has an outdated section on
> testing. It mentions that you should do a bootstrap for a change to
> the C front-end (should also be for the C++ front-end and I guess
> libstdc++ even if it isn't used much inside gcc).

	Jakub
Paolo Carlini - Sept. 23, 2013, 2:01 p.m.
On 9/23/13 8:22 AM, Andreas Schwab wrote:
> Paolo Carlini<paolo.carlini@oracle.com>  writes:
>
>> Hi
>>
>> Andreas Schwab<schwab@suse.de>  ha scritto:
>>
>>> What's wrong with always adding the instantiation?
>> That quite a few targets will not use it and will remain dead in the .so?
> How many uses are there for the unsigned long version?
I would say *all* the users of the library. Remember that these 
instantiations are in locale-inst.cc (I think an additional 
instantiation also belongs there, with a comment), and are now being 
"hijacked" for the new "pretty printing", but normally are used for 
formatted integers I/O.

Paolo.

Patch

Index: libstdc++-v3/include/bits/functexcept.h
===================================================================
--- libstdc++-v3/include/bits/functexcept.h	(revision 202709)
+++ libstdc++-v3/include/bits/functexcept.h	(working copy)
@@ -75,6 +75,10 @@ 
   __throw_out_of_range(const char*) __attribute__((__noreturn__));
 
   void
+  __throw_out_of_range_fmt(const char*, ...) __attribute__((__noreturn__))
+    __attribute__((__format__(__printf__, 1, 2)));
+
+  void
   __throw_runtime_error(const char*) __attribute__((__noreturn__));
 
   void
Index: libstdc++-v3/src/c++11/functexcept.cc
===================================================================
--- libstdc++-v3/src/c++11/functexcept.cc	(revision 202709)
+++ libstdc++-v3/src/c++11/functexcept.cc	(working copy)
@@ -31,6 +31,7 @@ 
 #include <future>
 #include <functional>
 #include <bits/regex_error.h>
+#include <stdarg.h>
 
 #ifdef _GLIBCXX_USE_NLS
 # include <libintl.h>
@@ -39,6 +40,12 @@ 
 # define _(msgid)   (msgid)
 #endif
 
+namespace __gnu_cxx
+{
+  int __snprintf_lite(char *__buf, size_t __bufsize, const char *__fmt,
+		      va_list __ap);
+}
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -80,6 +87,22 @@ 
   { _GLIBCXX_THROW_OR_ABORT(out_of_range(_(__s))); }
 
   void
+  __throw_out_of_range_fmt(const char* __fmt, ...)
+  {
+    const size_t __len = __builtin_strlen(__fmt);
+    // We expect at most 2 numbers, and 1 short string. The additional
+    // 512 bytes should provide more than enough space for expansion.
+    const size_t __alloca_size = __len + 512;
+    char *const __s = static_cast<char*>(__builtin_alloca(__alloca_size));
+    va_list __ap;
+
+    va_start(__ap, __fmt);
+    __gnu_cxx::__snprintf_lite(__s, __alloca_size, __fmt, __ap);
+    _GLIBCXX_THROW_OR_ABORT(out_of_range(_(__s)));
+    va_end(__ap);  // Not reached.
+  }
+
+  void
   __throw_runtime_error(const char* __s __attribute__((unused)))
   { _GLIBCXX_THROW_OR_ABORT(runtime_error(_(__s))); }
 
Index: libstdc++-v3/src/c++11/snprintf_lite.cc
===================================================================
--- libstdc++-v3/src/c++11/snprintf_lite.cc	(revision 0)
+++ libstdc++-v3/src/c++11/snprintf_lite.cc	(revision 0)
@@ -0,0 +1,152 @@ 
+// Debugging support -*- C++ -*-
+
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#include <stdarg.h>
+#include <bits/functexcept.h>
+#include <bits/locale_facets.h>
+
+namespace std {
+  template<typename _CharT, typename _ValueT>
+  int
+  __int_to_char(_CharT* __bufend, _ValueT __v, const _CharT* __lit,
+                ios_base::fmtflags __flags, bool __dec);
+}
+
+namespace __gnu_cxx {
+
+  // Private helper to throw logic error if snprintf_lite runs out
+  // of space (which is not expected to ever happen).
+  // NUL-terminates __buf.
+  void
+  __throw_insufficient_space(const char *__buf, const char *__bufend)
+    __attribute__((__noreturn__));
+
+  void
+  __throw_insufficient_space(const char *__buf, const char *__bufend)
+  {
+    // Include space for trailing NUL.
+    const size_t __len = __bufend - __buf + 1;
+
+    const char __err[] = "not enough space for format expansion "
+      "(Please submit full bug report at http://gcc.gnu.org/bugs.html):\n    ";
+    const size_t __errlen = sizeof(__err) - 1;
+
+    char *const __e
+      = static_cast<char*>(__builtin_alloca(__errlen + __len));
+
+    __builtin_memcpy(__e, __err, __errlen);
+    __builtin_memcpy(__e + __errlen, __buf, __len - 1);
+    __e[__errlen + __len - 1] = '\0';
+    std::__throw_logic_error(__e);
+  }
+
+
+  // Private routine to append decimal representation of VAL to the given
+  // BUFFER, but not more than BUFSIZE characters.
+  // Does not NUL-terminate the output buffer.
+  // Returns number of characters appended, or -1 if BUFSIZE is too small.
+  int __concat_size_t(char *__buf, size_t __bufsize, size_t __val)
+  {
+    // Long enough for decimal representation.
+    int __ilen = 3 * sizeof(__val);
+    char *__cs = static_cast<char*>(__builtin_alloca(__ilen));
+    size_t __len = std::__int_to_char(__cs + __ilen, __val,
+				      std::__num_base::_S_atoms_out,
+				      std::ios_base::dec, true);
+    if (__bufsize < __len)
+      return -1;
+
+    __builtin_memcpy(__buf, __cs + __ilen - __len, __len);
+    return __len;
+  }
+
+
+  // Private routine to print into __buf arguments according to format,
+  // not to exceed __bufsize.
+  // Only '%%', '%s' and '%zu' format specifiers are understood.
+  // Returns number of characters printed (excluding terminating NUL).
+  // Always NUL-terminates __buf.
+  // Throws logic_error on insufficient space.
+  int __snprintf_lite(char *__buf, size_t __bufsize, const char *__fmt,
+		      va_list __ap)
+  {
+    char *__d = __buf;
+    const char *__s = __fmt;
+    const char *const __limit = __d + __bufsize - 1;  // Leave space for NUL.
+
+    while (__s[0] != '\0' && __d < __limit)
+      {
+	if (__s[0] == '%')
+	  switch (__s[1])
+	    {
+	    default:  // Stray '%'. Just print it.
+	      break;
+	    case '%':  // '%%'
+	      __s += 1;
+	      break;
+	    case 's':  // '%s'.
+	      {
+		const char *__v = va_arg(__ap, const char *);
+
+		while (__v[0] != '\0' && __d < __limit)
+		  *__d++ = *__v++;
+
+		if (__v[0] != '\0')
+		  // Not enough space for __fmt expansion.
+		  __throw_insufficient_space(__buf, __d);
+
+		__s += 2;  // Step over %s.
+		continue;
+	      }
+	      break;
+	    case 'z':
+	      if (__s[2] == 'u')  // '%zu' -- expand next size_t arg.
+		{
+		  const int __len = __concat_size_t(__d, __limit - __d,
+						    va_arg(__ap, size_t));
+		  if (__len > 0)
+		    __d += __len;
+		  else
+		    // Not enough space for __fmt expansion.
+		    __throw_insufficient_space(__buf, __d);
+
+		  __s += 3;  // Step over %zu
+		  continue;
+		}
+	      // Stray '%zX'. Just print it.
+	      break;
+	    }
+	*__d++ = *__s++;
+      }
+
+    if (__s[0] != '\0')
+      // Not enough space for __fmt expansion.
+      __throw_insufficient_space(__buf, __d);
+
+    *__d = '\0';
+    return __d - __buf;
+  }
+
+}  // __gnu_cxx
Index: libstdc++-v3/src/c++11/Makefile.am
===================================================================
--- libstdc++-v3/src/c++11/Makefile.am	(revision 202709)
+++ libstdc++-v3/src/c++11/Makefile.am	(working copy)
@@ -42,6 +42,7 @@ 
 	random.cc \
 	regex.cc  \
 	shared_ptr.cc \
+	snprintf_lite.cc \
 	system_error.cc \
 	thread.cc
 
Index: libstdc++-v3/src/c++11/Makefile.in
===================================================================
--- libstdc++-v3/src/c++11/Makefile.in	(revision 202709)
+++ libstdc++-v3/src/c++11/Makefile.in	(working copy)
@@ -70,7 +70,8 @@ 
 am__objects_1 = chrono.lo condition_variable.lo debug.lo \
 	functexcept.lo functional.lo future.lo hash_c++0x.lo \
 	hashtable_c++0x.lo limits.lo mutex.lo placeholders.lo \
-	random.lo regex.lo shared_ptr.lo system_error.lo thread.lo
+	random.lo regex.lo shared_ptr.lo snprintf_lite.lo \
+	system_error.lo thread.lo
 @ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_2 = fstream-inst.lo \
 @ENABLE_EXTERN_TEMPLATE_TRUE@	string-inst.lo wstring-inst.lo
 am_libc__11convenience_la_OBJECTS = $(am__objects_1) $(am__objects_2)
@@ -324,6 +325,7 @@ 
 	random.cc \
 	regex.cc  \
 	shared_ptr.cc \
+	snprintf_lite.cc \
 	system_error.cc \
 	thread.cc
 
Index: libstdc++-v3/config/abi/pre/gnu.ver
===================================================================
--- libstdc++-v3/config/abi/pre/gnu.ver	(revision 202709)
+++ libstdc++-v3/config/abi/pre/gnu.ver	(working copy)
@@ -1365,6 +1365,9 @@ 
     # std::get_unexpected()
     _ZSt14get_unexpectedv;
 
+    # std::__throw_out_of_range_fmt(char const*, ...)
+    _ZSt24__throw_out_of_range_fmtPKcz;
+
 } GLIBCXX_3.4.19;
 
 # Symbols in the support library (libsupc++) have their own tag.
Index: libstdc++-v3/include/std/array
===================================================================
--- libstdc++-v3/include/std/array	(revision 202709)
+++ libstdc++-v3/include/std/array	(working copy)
@@ -180,7 +180,9 @@ 
       at(size_type __n)
       {
 	if (__n >= _Nm)
-	  std::__throw_out_of_range(__N("array::at"));
+	  std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) "
+					    ">= _Nm (which is %zu)"),
+					__n, _Nm);
 	return _AT_Type::_S_ref(_M_elems, __n);
       }
 
@@ -190,7 +192,9 @@ 
 	// Result of conditional expression must be an lvalue so use
 	// boolean ? lvalue : (throw-expr, lvalue)
 	return __n < _Nm ? _AT_Type::_S_ref(_M_elems, __n)
-	  : (std::__throw_out_of_range(__N("array::at")),
+	  : (std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) "
+					       ">= _Nm (which is %zu)"),
+					   __n, _Nm),
 	     _AT_Type::_S_ref(_M_elems, 0));
       }
 
Index: libstdc++-v3/include/debug/array
===================================================================
--- libstdc++-v3/include/debug/array	(revision 202709)
+++ libstdc++-v3/include/debug/array	(working copy)
@@ -165,7 +165,10 @@ 
       at(size_type __n)
       {
 	if (__n >= _Nm)
-	  std::__throw_out_of_range(__N("array::at"));
+	  std::__throw_out_of_range_fmt(__N("array::at: __n "
+				            "(which is %zu) >= _Nm "
+					    "(which is %zu)"),
+					__n, _Nm);
 	return _AT_Type::_S_ref(_M_elems, __n);
       }
 
@@ -175,7 +178,9 @@ 
 	// Result of conditional expression must be an lvalue so use
 	// boolean ? lvalue : (throw-expr, lvalue)
 	return __n < _Nm ? _AT_Type::_S_ref(_M_elems, __n)
-	  : (std::__throw_out_of_range(__N("array::at")),
+	  : (std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) "
+					       ">= _Nm (which is %zu)"),
+					   __n, _Nm),
 	     _AT_Type::_S_ref(_M_elems, 0));
       }
 
Index: libstdc++-v3/include/profile/array
===================================================================
--- libstdc++-v3/include/profile/array	(revision 202709)
+++ libstdc++-v3/include/profile/array	(working copy)
@@ -138,7 +138,10 @@ 
       at(size_type __n)
       {
 	if (__n >= _Nm)
-	  std::__throw_out_of_range(__N("array::at"));
+	  std::__throw_out_of_range_fmt(__N("array::at: __n "
+				            "(which is %zu) >= _Nm "
+					    "(which is %zu)"),
+					__n, _Nm);
 	return _AT_Type::_S_ref(_M_elems, __n);
       }
 
@@ -148,7 +151,9 @@ 
 	// Result of conditional expression must be an lvalue so use
 	// boolean ? lvalue : (throw-expr, lvalue)
 	return __n < _Nm ? _AT_Type::_S_ref(_M_elems, __n)
-	  : (std::__throw_out_of_range(__N("array::at")),
+	  : (std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) "
+					       ">= _Nm (which is %zu)"),
+					   __n, _Nm),
 	     _AT_Type::_S_ref(_M_elems, 0));
       }
 
Index: libstdc++-v3/include/std/bitset
===================================================================
--- libstdc++-v3/include/std/bitset	(revision 202709)
+++ libstdc++-v3/include/std/bitset	(working copy)
@@ -752,7 +752,27 @@ 
       typedef _Base_bitset<_GLIBCXX_BITSET_WORDS(_Nb)> _Base;
       typedef unsigned long _WordT;
 
+      template<class _CharT, class _Traits, class _Alloc>
       void
+      _M_check_initial_position(const std::basic_string<_CharT, _Traits, _Alloc>& __s,
+				size_t __position) const
+      {
+	if (__position > __s.size())
+	  __throw_out_of_range_fmt(__N("bitset::bitset: __position "
+				       "(which is %zu) > __s.size() "
+				       "(which is %zu)"),
+				   __position, __s.size());
+      }
+
+      void _M_check(size_t __position, const char *__s) const
+      {
+	if (__position >= _Nb)
+	  __throw_out_of_range_fmt(__N("%s: __position (which is %zu) "
+				       ">= _Nb (which is %zu)"),
+				   __s, __position, _Nb);
+      }
+
+      void
       _M_do_sanitize() _GLIBCXX_NOEXCEPT
       { 
 	typedef _Sanitize<_Nb % _GLIBCXX_BITSET_BITS_PER_WORD> __sanitize_type;
@@ -867,9 +887,7 @@ 
 	       size_t __position = 0)
 	: _Base()
 	{
-	  if (__position > __s.size())
-	    __throw_out_of_range(__N("bitset::bitset initial position "
-				     "not valid"));
+	  _M_check_initial_position(__s, __position);
 	  _M_copy_from_string(__s, __position,
 			      std::basic_string<_CharT, _Traits, _Alloc>::npos,
 			      _CharT('0'), _CharT('1'));
@@ -890,9 +908,7 @@ 
 	       size_t __position, size_t __n)
 	: _Base()
 	{
-	  if (__position > __s.size())
-	    __throw_out_of_range(__N("bitset::bitset initial position "
-				     "not valid"));
+	  _M_check_initial_position(__s, __position);
 	  _M_copy_from_string(__s, __position, __n, _CharT('0'), _CharT('1'));
 	}
 
@@ -904,9 +920,7 @@ 
 	       _CharT __zero, _CharT __one = _CharT('1'))
 	: _Base()
 	{
-	  if (__position > __s.size())
-	    __throw_out_of_range(__N("bitset::bitset initial position "
-				     "not valid"));
+	  _M_check_initial_position(__s, __position);
 	  _M_copy_from_string(__s, __position, __n, __zero, __one);
 	}
 
@@ -1067,8 +1081,7 @@ 
       bitset<_Nb>&
       set(size_t __position, bool __val = true)
       {
-	if (__position >= _Nb)
-	  __throw_out_of_range(__N("bitset::set"));
+	this->_M_check(__position, __N("bitset::set"));
 	return _Unchecked_set(__position, __val);
       }
 
@@ -1092,8 +1105,7 @@ 
       bitset<_Nb>&
       reset(size_t __position)
       {
-	if (__position >= _Nb)
-	  __throw_out_of_range(__N("bitset::reset"));
+	this->_M_check(__position, __N("bitset::reset"));
 	return _Unchecked_reset(__position);
       }
       
@@ -1116,8 +1128,7 @@ 
       bitset<_Nb>&
       flip(size_t __position)
       {
-	if (__position >= _Nb)
-	  __throw_out_of_range(__N("bitset::flip"));
+	this->_M_check(__position, __N("bitset::flip"));
 	return _Unchecked_flip(__position);
       }
       
@@ -1302,8 +1313,7 @@ 
       bool
       test(size_t __position) const
       {
-	if (__position >= _Nb)
-	  __throw_out_of_range(__N("bitset::test"));
+	this->_M_check(__position, __N("bitset::test"));
 	return _Unchecked_test(__position);
       }
 
Index: libstdc++-v3/include/ext/vstring.h
===================================================================
--- libstdc++-v3/include/ext/vstring.h	(revision 202709)
+++ libstdc++-v3/include/ext/vstring.h	(working copy)
@@ -85,7 +85,9 @@ 
       _M_check(size_type __pos, const char* __s) const
       {
 	if (__pos > this->size())
-	  std::__throw_out_of_range(__N(__s));
+	  std::__throw_out_of_range_fmt(__N("%s: __pos (which is %zu) > "
+					    "this->size() (which is %zu)"),
+					__s, __pos, this->size());
 	return __pos;
       }
 
@@ -581,7 +583,10 @@ 
       at(size_type __n) const
       {
 	if (__n >= this->size())
-	  std::__throw_out_of_range(__N("__versa_string::at"));
+	  std::__throw_out_of_range_fmt(__N("__versa_string::at: __n "
+					    "(which is %zu) >= this->size() "
+					    "(which is %zu)"),
+					__n, this->size());
 	return this->_M_data()[__n];
       }
 
@@ -600,7 +605,10 @@ 
       at(size_type __n)
       {
 	if (__n >= this->size())
-	  std::__throw_out_of_range(__N("__versa_string::at"));
+	  std::__throw_out_of_range_fmt(__N("__versa_string::at: __n "
+					    "(which is %zu) >= this->size() "
+					    "(which is %zu)"),
+					__n, this->size());
 	this->_M_leak();
 	return this->_M_data()[__n];
       }
Index: libstdc++-v3/include/bits/stl_deque.h
===================================================================
--- libstdc++-v3/include/bits/stl_deque.h	(revision 202709)
+++ libstdc++-v3/include/bits/stl_deque.h	(working copy)
@@ -1269,7 +1269,10 @@ 
       _M_range_check(size_type __n) const
       {
 	if (__n >= this->size())
-	  __throw_out_of_range(__N("deque::_M_range_check"));
+	  __throw_out_of_range_fmt(__N("deque::_M_range_check: __n "
+				       "(which is %zu)>= this->size() "
+				       "(which is %zu)"),
+				   __n, this->size());
       }
 
     public:
Index: libstdc++-v3/include/bits/stl_bvector.h
===================================================================
--- libstdc++-v3/include/bits/stl_bvector.h	(revision 202709)
+++ libstdc++-v3/include/bits/stl_bvector.h	(working copy)
@@ -785,7 +785,10 @@ 
     _M_range_check(size_type __n) const
     {
       if (__n >= this->size())
-        __throw_out_of_range(__N("vector<bool>::_M_range_check"));
+	__throw_out_of_range_fmt(__N("vector<bool>::_M_range_check: __n "
+				     "(which is %zu) >= this->size() "
+				     "(which is %zu)"),
+				 __n, this->size());
     }
 
   public:
Index: libstdc++-v3/include/bits/basic_string.h
===================================================================
--- libstdc++-v3/include/bits/basic_string.h	(revision 202709)
+++ libstdc++-v3/include/bits/basic_string.h	(working copy)
@@ -321,7 +321,9 @@ 
       _M_check(size_type __pos, const char* __s) const
       {
 	if (__pos > this->size())
-	  __throw_out_of_range(__N(__s));
+	  __throw_out_of_range_fmt(__N("%s: __pos (which is %zu) > "
+				       "this->size() (which is %zu)"),
+				   __s, __pos, this->size());
 	return __pos;
       }
 
@@ -865,7 +867,10 @@ 
       at(size_type __n) const
       {
 	if (__n >= this->size())
-	  __throw_out_of_range(__N("basic_string::at"));
+	  __throw_out_of_range_fmt(__N("basic_string::at: __n "
+				       "(which is %zu) >= this->size() "
+				       "(which is %zu)"),
+				   __n, this->size());
 	return _M_data()[__n];
       }
 
@@ -884,7 +889,10 @@ 
       at(size_type __n)
       {
 	if (__n >= size())
-	  __throw_out_of_range(__N("basic_string::at"));
+	  __throw_out_of_range_fmt(__N("basic_string::at: __n "
+				       "(which is %zu) >= this->size() "
+				       "(which is %zu)"),
+				   __n, this->size());
 	_M_leak();
 	return _M_data()[__n];
       }
Index: libstdc++-v3/include/bits/stl_vector.h
===================================================================
--- libstdc++-v3/include/bits/stl_vector.h	(revision 202709)
+++ libstdc++-v3/include/bits/stl_vector.h	(working copy)
@@ -785,7 +785,10 @@ 
       _M_range_check(size_type __n) const
       {
 	if (__n >= this->size())
-	  __throw_out_of_range(__N("vector::_M_range_check"));
+	  __throw_out_of_range_fmt(__N("vector::_M_range_check: __n "
+				       "(which is %zu) >= this->size() "
+				       "(which is %zu)"),
+				   __n, this->size());
       }
 
     public:
Index: libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc	(revision 202709)
+++ libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1302 }
+// { dg-error "no matching" "" { target *-*-* } 1305 }
 
 #include <vector>
 
Index: libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc	(revision 202709)
+++ libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1343 }
+// { dg-error "no matching" "" { target *-*-* } 1346 }
 
 #include <vector>
 
Index: libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc	(revision 202709)
+++ libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1228 }
+// { dg-error "no matching" "" { target *-*-* } 1231 }
 
 #include <vector>
 
Index: libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc	(revision 202709)
+++ libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1228 }
+// { dg-error "no matching" "" { target *-*-* } 1231 }
 
 #include <vector>
 #include <utility>
Index: libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc	(revision 202709)
+++ libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1760 }
+// { dg-error "no matching" "" { target *-*-* } 1763 }
 
 #include <deque>
 
Index: libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc	(revision 202709)
+++ libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1844 }
+// { dg-error "no matching" "" { target *-*-* } 1847 }
 
 #include <deque>
 
@@ -32,4 +32,3 @@ 
   std::deque<A> d;
   d.insert(d.begin(), 10, 1);
 }
-
Index: libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc	(revision 202709)
+++ libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1693 }
+// { dg-error "no matching" "" { target *-*-* } 1696 }
 
 #include <deque>
 
Index: libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc	(revision 202709)
+++ libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc	(working copy)
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1693 }
+// { dg-error "no matching" "" { target *-*-* } 1696 }
 
 #include <deque>
 #include <utility>
Index: libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc	(revision 202709)
+++ libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc	(working copy)
@@ -28,6 +28,6 @@ 
 int n2 = std::get<1>(std::move(a));
 int n3 = std::get<1>(ca);
 
-// { dg-error "static assertion failed" "" { target *-*-* } 270 }
-// { dg-error "static assertion failed" "" { target *-*-* } 279 }
-// { dg-error "static assertion failed" "" { target *-*-* } 287 }
+// { dg-error "static assertion failed" "" { target *-*-* } 274 }
+// { dg-error "static assertion failed" "" { target *-*-* } 283 }
+// { dg-error "static assertion failed" "" { target *-*-* } 291 }
Index: libstdc++-v3/testsuite/23_containers/array/tuple_interface/tuple_element_neg.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/array/tuple_interface/tuple_element_neg.cc	(revision 202709)
+++ libstdc++-v3/testsuite/23_containers/array/tuple_interface/tuple_element_neg.cc	(working copy)
@@ -23,4 +23,4 @@ 
 
 typedef std::tuple_element<1, std::array<int, 1>>::type type;
 
-// { dg-error "static assertion failed" "" { target *-*-* } 316 }
+// { dg-error "static assertion failed" "" { target *-*-* } 320 }
Index: libstdc++-v3/testsuite/util/exception/safety.h
===================================================================
--- libstdc++-v3/testsuite/util/exception/safety.h	(revision 202709)
+++ libstdc++-v3/testsuite/util/exception/safety.h	(working copy)
@@ -47,22 +47,12 @@ 
       const typename distribution_type::param_type p(0, __max_size);
       size_type random = generator(p);
       if (random < distribution.min() || random > distribution.max())
-	{
-	  std::string __s("setup_base::generate");
-	  __s += "\n";
-	  __s += "random number generated is: ";
-	  char buf[40];
-	  __builtin_sprintf(buf, "%lu", (unsigned long)random);
-	  __s += buf;
-	  __s += " on range [";
-	  __builtin_sprintf(buf, "%lu", (unsigned long)distribution.min());
-	  __s += buf;
-	  __s += ", ";
-	  __builtin_sprintf(buf, "%lu", (unsigned long)distribution.max());
-	  __s += buf;
-	  __s += "]\n";
-	  std::__throw_out_of_range(__s.c_str());
-	}
+	std::__throw_out_of_range_fmt(__N("setup_base::generate\n"
+					  "random number generated is: %zu "
+					  "out of range [%zu, %zu]\n"),
+				      (size_t)random,
+				      (size_t)distribution.min(),
+				      (size_t)distribution.max());
       return random;
     }