commit 502928c8061343e82e982e06299c11d465f64b6c Author: Jonathan Wakely Date: Wed Sep 30 14:10:58 2015 +0100 Save-and-restore errno more carefully in libstdc++ * doc/xml/manual/diagnostics.xml: Document use of errno. * config/locale/generic/c_locale.cc (_Save_errno): New helper. (__convert_to_v): Use _Save_errno. * include/ext/string_conversions.h (__stoa): Only restore errno when it isn't set to non-zero. diff --git a/libstdc++-v3/config/locale/generic/c_locale.cc b/libstdc++-v3/config/locale/generic/c_locale.cc index 6da5f22..8dfea6b 100644 --- a/libstdc++-v3/config/locale/generic/c_locale.cc +++ b/libstdc++-v3/config/locale/generic/c_locale.cc @@ -44,6 +44,16 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION + namespace + { + struct _Save_errno + { + _Save_errno() : _M_errno(errno) { errno = 0; } + ~_Save_errno() { if (errno == 0) errno = _M_errno; } + int _M_errno; + }; + } + template<> void __convert_to_v(const char* __s, float& __v, ios_base::iostate& __err, @@ -59,7 +69,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool __overflow = false; #if !__FLT_HAS_INFINITY__ - errno = 0; + const _Save_errno __save_errno; #endif #ifdef _GLIBCXX_HAVE_STRTOF @@ -123,7 +133,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION char* __sanity; #if !__DBL_HAS_INFINITY__ - errno = 0; + const _Save_errno __save_errno; #endif __v = strtod(__s, &__sanity); @@ -167,7 +177,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION setlocale(LC_ALL, "C"); #if !__LDBL_HAS_INFINITY__ - errno = 0; + const _Save_errno __save_errno; #endif #if defined(_GLIBCXX_HAVE_STRTOLD) && !defined(_GLIBCXX_HAVE_BROKEN_STRTOLD) diff --git a/libstdc++-v3/doc/xml/manual/diagnostics.xml b/libstdc++-v3/doc/xml/manual/diagnostics.xml index 88ed2e2..3ceb5b3 100644 --- a/libstdc++-v3/doc/xml/manual/diagnostics.xml +++ b/libstdc++-v3/doc/xml/manual/diagnostics.xml @@ -71,6 +71,38 @@ +
Use of errno by the library + + + The C and POSIX standards guarantee that errno + is never set to zero by any library function. + The C++ standard has less to say about when errno + is or isn't set, but libstdc++ follows the same rule and never sets + it to zero. + + + + On the other hand, there are few guarantees about when the C++ library + sets errno on error, beyond what is specified for + functions that come from the C library. + For example, when std::stoi throws an exception of + type std::out_of_range, errno + may or may not have been set to ERANGE. + + + + Parts of the C++ library may be implemented in terms of C library + functions, which may result in errno being set + with no explicit call to a C function. For example, on a target where + operator new uses malloc + a failed memory allocation with operator new might + set errno to ENOMEM. + Which C++ library functions can set errno in this way + is unspecified because it may vary between platforms and between releases. + + +
+
Concept Checking diff --git a/libstdc++-v3/include/ext/string_conversions.h b/libstdc++-v3/include/ext/string_conversions.h index 58387a2..7f37e69 100644 --- a/libstdc++-v3/include/ext/string_conversions.h +++ b/libstdc++-v3/include/ext/string_conversions.h @@ -58,8 +58,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Ret __ret; _CharT* __endptr; - const int __saved_errno = errno; - errno = 0; + + struct _Save_errno { + _Save_errno() : _M_errno(errno) { errno = 0; } + ~_Save_errno() { if (errno == 0) errno = _M_errno; } + int _M_errno; + } const __save_errno; + const _TRet __tmp = __convf(__str, &__endptr, __base...); if (__endptr == __str) @@ -71,7 +76,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::__throw_out_of_range(__name); else __ret = __tmp; - errno = __saved_errno; if (__idx) *__idx = __endptr - __str;