public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-8129] libstdc++: Use strerror_r in std::generic_category()::message(int) [PR110133]
@ 2023-12-06 14:44 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2023-12-06 14:44 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:ca233ac9ba085e2acd385bda6a778684a0c96694

commit r13-8129-gca233ac9ba085e2acd385bda6a778684a0c96694
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Nov 3 13:59:48 2023 +0000

    libstdc++: Use strerror_r in std::generic_category()::message(int) [PR110133]
    
    Use strerror_r instead of strerror when available, due to the latter not
    being thread-safe. This is complicated by Glibc providing a GNU-specific
    strerror_r which is not compatible with POSIX strerror_r, so we need to
    dispatch on the return type.
    
    Because we estimate the initial std::string buffer size we might end up
    with excess capacity in the returned std::string. We can slightly tweak
    the std::system_error constructors to make use of that excess capacity,
    so that in some cases we require fewer allocations to construct the
    std::system_error::what() string.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/110133
            * include/std/system_error (system_error::system_error): Group
            arguments so that concatenation can reuse rvalue's capacity.
            * src/c++11/system_error.cc (strerror_string): New function.
            [_GLIBCXX_HAVE_STRERROR_R] (use_strerror_result): New functions.
            (generic_error_category::message): Use strerror_string.
            (system_error_category::message): Likewise.
    
    (cherry picked from commit 51f94778b45514992a716b0b2d7a87244e6f0018)

Diff:
---
 libstdc++-v3/include/std/system_error  |  4 +-
 libstdc++-v3/src/c++11/system_error.cc | 81 ++++++++++++++++++++++++++++++----
 2 files changed, 75 insertions(+), 10 deletions(-)

diff --git a/libstdc++-v3/include/std/system_error b/libstdc++-v3/include/std/system_error
index d71abc9766b..e26472bb0bf 100644
--- a/libstdc++-v3/include/std/system_error
+++ b/libstdc++-v3/include/std/system_error
@@ -563,7 +563,7 @@ namespace __adl_only
     : runtime_error(__ec.message()), _M_code(__ec) { }
 
     system_error(error_code __ec, const string& __what)
-    : runtime_error(__what + ": " + __ec.message()), _M_code(__ec) { }
+    : runtime_error(__what + (": " + __ec.message())), _M_code(__ec) { }
 
     system_error(error_code __ec, const char* __what)
     : runtime_error(__what + (": " + __ec.message())), _M_code(__ec) { }
@@ -576,7 +576,7 @@ namespace __adl_only
       _M_code(__v, __ecat) { }
 
     system_error(int __v, const error_category& __ecat, const string& __what)
-    : runtime_error(__what + ": " + error_code(__v, __ecat).message()),
+    : runtime_error(__what + (": " + error_code(__v, __ecat).message())),
       _M_code(__v, __ecat) { }
 
 #if __cplusplus >= 201103L
diff --git a/libstdc++-v3/src/c++11/system_error.cc b/libstdc++-v3/src/c++11/system_error.cc
index 748eee94168..50033597c06 100644
--- a/libstdc++-v3/src/c++11/system_error.cc
+++ b/libstdc++-v3/src/c++11/system_error.cc
@@ -46,6 +46,77 @@ namespace
 {
   using std::string;
 
+#if _GLIBCXX_HAVE_STRERROR_R
+  // Handle the result of POSIX strerror_r.
+  inline std::size_t
+  use_strerror_result(int res, char* buf, std::size_t bufsz,
+		      std::size_t& nextbufsz)
+  {
+    if (res == 0) // Success.
+      return std::strlen(buf);
+
+    if (res == ERANGE) // Buffer too small to hold result string.
+      {
+	nextbufsz = 2 * bufsz;
+	return 0;
+      }
+    // else res == EINVAL, unknown error.
+    if (*buf == '\0') // No result string written to buffer.
+      {
+	const char msg[] = "Unknown error";
+	std::memcpy(buf, msg, sizeof(msg) - 1);
+	return sizeof(msg) - 1;
+      }
+    else // An "unknown error" string was already written to the buffer.
+      return std::strlen(buf);
+  }
+
+  // Handle the result of GNU strerror_r.
+  inline std::size_t
+  use_strerror_result(char* res, char* buf, std::size_t bufsz,
+		      std::size_t& nextbufsz)
+  {
+    if (res == buf) // Result string written to the buffer.
+      return std::strlen(res);
+
+    // Static result string returned, must be copied to the buffer.
+    std::size_t len = std::strlen(res);
+    if (len <= bufsz)
+      {
+	std::strcpy(buf, res);
+	return len;
+      }
+
+    // Reallocate and try again:
+    nextbufsz = len;
+    return 0;
+  }
+
+  string strerror_string(int err)
+  {
+    // Estimate maximum length of strerror strings (including "Unknown error").
+    // Any excess capacity here can be used by std::system_error constructors
+    // when concatenating strings.
+    std::size_t len = 60;
+    string s;
+    do
+      {
+	s.resize(len);
+	char* p = &s.front();
+	std::size_t n = len;
+	n = use_strerror_result(strerror_r(err, p, n), p, n, len);
+	s.resize(n);
+      }
+    while (s.empty());
+    return s;
+  }
+#else
+  string strerror_string(int err)
+  {
+    return strerror(err); // XXX Not thread-safe.
+  }
+#endif
+
   template<typename T>
     struct constant_init
     {
@@ -66,11 +137,7 @@ namespace
     _GLIBCXX_DEFAULT_ABI_TAG
     string
     message(int i) const final
-    {
-      // XXX locale issues: how does one get or set loc.
-      // _GLIBCXX_HAVE_STRERROR_L, strerror_l(i, cloc)
-      return string(strerror(i));
-    }
+    { return strerror_string(i); }
 
     // Override this to avoid a virtual call to default_error_condition(i).
     bool
@@ -113,9 +180,7 @@ namespace
       }
       return string("Unknown error code");
 #else
-      // XXX locale issues: how does one get or set loc.
-      // _GLIBCXX_HAVE_STRERROR_L, strerror_l(i, cloc)
-      return string(strerror(i));
+      return strerror_string(i);
 #endif
     }

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-12-06 14:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-06 14:44 [gcc r13-8129] libstdc++: Use strerror_r in std::generic_category()::message(int) [PR110133] Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).