On 02/06/2011 02:54 AM, Corinna Vinschen wrote:
>> We already provide our own strerror() (it provides a better experience
>> for out-of-range values that the newlib interface), but we're currently
>> using the newlib strerror_r() (in spite of its truncation flaw).
>>
>> How should I rework this patch?
> 
> It would be better if we implement strerror_r locally, in two versions,
> just as on Linux.  I think the best approach is to implement this in
> newlib first (I replied to your mail there) and then, given that we use
> the newlib string.h, copy the method over to Cygwin to match our current
> strerror more closely.

Here's the cygwin side of things, to match newlib's <string.h> changes.
 Surprisingly, strerror_r turned out to be identical even when based on
different root strerror(), so I left that inside #if 0, but it's easy
enough to kill the #if 0 if you don't want cygwin to use any of newlib's
strerror*.

---
 winsup/cygwin/ChangeLog                |    9 +++
 winsup/cygwin/cygwin.din               |    1 +
 winsup/cygwin/errno.cc                 |   84
+++++++++++++++++++++-----------
 winsup/cygwin/include/cygwin/version.h |    3 +-
 4 files changed, 68 insertions(+), 29 deletions(-)

2011-02-09  Eric Blake  <ebl...@redhat.com>

        * errno.cc (__xpg_strerror_r): New function.
        (strerror_r): Update comments to match newlib's fixes.
        (strerror): Set errno on failure.
        (_sys_errlist): Cause EINVAL failure for reserved values.
        * cygwin.din: Export new function.
        * include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.

-- 
Eric Blake   ebl...@redhat.com    +1-801-349-2682
Libvirt virtualization library http://libvirt.org
diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din
index 2e7e647..780179a 100644
--- a/winsup/cygwin/cygwin.din
+++ b/winsup/cygwin/cygwin.din
@@ -1933,6 +1933,7 @@ xdrrec_skiprecord SIGFE
 __xdrrec_getrec SIGFE
 __xdrrec_setnonblock SIGFE
 xdrstdio_create SIGFE
+__xpg_strerror_r SIGFE
 y0 NOSIGFE
 y0f NOSIGFE
 y1 NOSIGFE
diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc
index a9860f4..0e9c863 100644
--- a/winsup/cygwin/errno.cc
+++ b/winsup/cygwin/errno.cc
@@ -199,9 +199,9 @@ const char *_sys_errlist[] NO_COPY_INIT =
 /* EL2HLT 44 */                  "Level 2 halted",
 /* EDEADLK 45 */         "Resource deadlock avoided",
 /* ENOLCK 46 */                  "No locks available",
-                         "error 47",
-                         "error 48",
-                         "error 49",
+                         NULL,
+                         NULL,
+                         NULL,
 /* EBADE 50 */           "Invalid exchange",
 /* EBADR 51 */           "Invalid request descriptor",
 /* EXFULL 52 */                  "Exchange full",
@@ -210,8 +210,8 @@ const char *_sys_errlist[] NO_COPY_INIT =
 /* EBADSLT 55 */         "Invalid slot",
 /* EDEADLOCK 56 */       "File locking deadlock error",
 /* EBFONT 57 */                  "Bad font file format",
-                         "error 58",
-                         "error 59",
+                         NULL,
+                         NULL,
 /* ENOSTR 60 */                  "Device not a stream",
 /* ENODATA 61 */         "No data available",
 /* ETIME 62 */           "Timer expired",
@@ -224,13 +224,13 @@ const char *_sys_errlist[] NO_COPY_INIT =
 /* ESRMNT 69 */                  "Srmount error",
 /* ECOMM 70 */           "Communication error on send",
 /* EPROTO 71 */                  "Protocol error",
-                         "error 72",
-                         "error 73",
+                         NULL,
+                         NULL,
 /* EMULTIHOP 74 */       "Multihop attempted",
 /* ELBIN 75 */           "Inode is remote (not really error)",
 /* EDOTDOT 76 */         "RFS specific error",
 /* EBADMSG 77 */         "Bad message",
-                         "error 78",
+                         NULL,
 /* EFTYPE 79 */                  "Inappropriate file type or format",
 /* ENOTUNIQ 80 */        "Name not unique on network",
 /* EBADFD 81 */                  "File descriptor in bad state",
@@ -245,17 +245,17 @@ const char *_sys_errlist[] NO_COPY_INIT =
 /* ENOTEMPTY 90        */        "Directory not empty",
 /* ENAMETOOLONG 91 */    "File name too long",
 /* ELOOP 92 */           "Too many levels of symbolic links",
-                         "error 93",
-                         "error 94",
+                         NULL,
+                         NULL,
 /* EOPNOTSUPP 95 */      "Operation not supported",
 /* EPFNOSUPPORT 96 */    "Protocol family not supported",
-                         "error 97",
-                         "error 98",
-                         "error 99",
-                         "error 100",
-                         "error 101",
-                         "error 102",
-                         "error 103",
+                         NULL,
+                         NULL,
+                         NULL,
+                         NULL,
+                         NULL,
+                         NULL,
+                         NULL,
 /* ECONNRESET 104 */     "Connection reset by peer",
 /* ENOBUFS 105 */        "No buffer space available",
 /* EAFNOSUPPORT 106 */   "Address family not supported by protocol",
@@ -357,27 +357,55 @@ strerror_worker (int errnum)
   return res;
 }

-/* strerror: convert from errno values to error strings */
+/* strerror: convert from errno values to error strings.  Newlib's
+   strerror_r returns "" for unknown values, so we override it to
+   provide a nicer thread-safe result string and set errno.  */
 extern "C" char *
 strerror (int errnum)
 {
   char *errstr = strerror_worker (errnum);
   if (!errstr)
-    __small_sprintf (errstr = _my_tls.locals.strerror_buf, "Unknown error %u",
-                    (unsigned) errnum);
+    {
+      __small_sprintf (errstr = _my_tls.locals.strerror_buf, "Unknown error 
%u",
+                      (unsigned) errnum);
+      errno = _impure_ptr->_errno = EINVAL;
+    }
   return errstr;
 }

+/* Newlib's <string.h> provides declarations for two strerror_r
+   variants, according to preprocessor feature macros.  It does the
+   right thing for GNU strerror_r, but its __xpg_strerror_r mishandles
+   a case of EINVAL when coupled with our strerror() override.*/
 #if 0
-extern "C" int
+extern "C" char *
 strerror_r (int errnum, char *buf, size_t n)
 {
-  char *errstr = strerror_worker (errnum);
-  if (!errstr)
-    return EINVAL;
-  if (strlen (errstr) >= n)
-    return ERANGE;
-  strcpy (buf, errstr);
-  return 0;
+  char *error = strerror (errnum);
+  if (strlen (error) >= n)
+    return error;
+  return strcpy (buf, error);
 }
 #endif
+
+extern "C" int
+__xpg_strerror_r (int errnum, char *buf, size_t n)
+{
+  if (!n)
+    return ERANGE;
+  int result = 0;
+  char *error = strerror_worker (errnum);
+    {
+      __small_sprintf (error = _my_tls.locals.strerror_buf, "Unknown error %u",
+                      (unsigned) errnum);
+      result = EINVAL;
+    }
+  if (strlen (error) >= n)
+    {
+      memcpy (buf, error, n - 1);
+      buf[n - 1] = '\0';
+      return ERANGE;
+    }
+  strcpy (buf, error);
+  return result;
+}
diff --git a/winsup/cygwin/include/cygwin/version.h 
b/winsup/cygwin/include/cygwin/version.h
index c757827..7246e8e 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -399,12 +399,13 @@ details. */
       233: Add TIOCGPGRP, TIOCSPGRP.  Export llround, llroundf.
       234: Export program_invocation_name, program_invocation_short_name.
       235: Export madvise.
+      236: Export __xpg_strerror_r.
      */

      /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */

 #define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 235
+#define CYGWIN_VERSION_API_MINOR 236

      /* There is also a compatibity version number associated with the
        shared memory regions.  It is incremented when incompatible
-- 
1.7.3.3

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to