]> granicus.if.org Git - curl/commitdiff
ensure that errno is not modified inside Curl_strerror()
authorYang Tse <yangsita@gmail.com>
Fri, 12 Sep 2008 10:51:57 +0000 (10:51 +0000)
committerYang Tse <yangsita@gmail.com>
Fri, 12 Sep 2008 10:51:57 +0000 (10:51 +0000)
lib/strerror.c

index f1d22e14374d2d5850ccb5cdb2d25e8ab33a02bc..526187bb871f48f47d3f1da3d4819b3f078c4d59 100644 (file)
 #include "setup.h"
 
 #ifdef HAVE_STRERROR_R
-#if !defined(HAVE_POSIX_STRERROR_R) && !defined(HAVE_GLIBC_STRERROR_R)
-#error "you MUST have either POSIX or glibc strerror_r if strerror_r is found"
-#endif /* !POSIX && !glibc */
-#endif /* HAVE_STRERROR_R */
+#  if (!defined(HAVE_POSIX_STRERROR_R) && !defined(HAVE_GLIBC_STRERROR_R)) || \
+       (defined(HAVE_POSIX_STRERROR_R) &&  defined(HAVE_GLIBC_STRERROR_R))
+#    error "strerror_r MUST be either POSIX-style or glibc-style"
+#  endif
+#endif
 
 #include <curl/curl.h>
 #include <stdlib.h>
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
 
-#if defined(HAVE_STRERROR_R) && defined(HAVE_NO_STRERROR_R_DECL)
-#ifdef HAVE_POSIX_STRERROR_R
-/* seen on AIX 5100-02 gcc 2.9 */
-extern int strerror_r(int errnum, char *strerrbuf, size_t buflen);
-#else
-extern char *strerror_r(int errnum, char *buf, size_t buflen);
-#endif
-#endif
 
 const char *
 curl_easy_strerror(CURLcode error)
@@ -590,6 +583,7 @@ const char *Curl_strerror(struct connectdata *conn, int err)
 {
   char *buf, *p;
   size_t max;
+  int old_errno = ERRNO;
 
   DEBUGASSERT(conn);
   DEBUGASSERT(err >= 0);
@@ -601,17 +595,15 @@ const char *Curl_strerror(struct connectdata *conn, int err)
 #ifdef USE_WINSOCK
 
 #ifdef _WIN32_WCE
-  buf[0]=0;
   {
     wchar_t wbuf[256];
+    wbuf[0] = L'\0';
 
     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
                   LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL);
     wcstombs(buf,wbuf,max);
   }
-
 #else
-
   /* 'sys_nerr' is the maximum errno number, it is not widely portable */
   if(err >= 0 && err < sys_nerr)
     strncpy(buf, strerror(err), max);
@@ -622,34 +614,43 @@ const char *Curl_strerror(struct connectdata *conn, int err)
       snprintf(buf, max, "Unknown error %d (%#x)", err, err);
   }
 #endif
+
 #else /* not USE_WINSOCK coming up */
 
-  /* These should be atomic and hopefully thread-safe */
-#ifdef HAVE_STRERROR_R
-  /* There are two different APIs for strerror_r(). The POSIX and the GLIBC
-     versions. */
-#ifdef HAVE_POSIX_STRERROR_R
-  strerror_r(err, buf, max);
-  /* this may set errno to ERANGE if insufficient storage was supplied via
-     'strerrbuf' and 'buflen' to contain the generated message string, or
-     EINVAL if the value of 'errnum' is not a valid error number.*/
-#else
+#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
+ /*
+  * The POSIX-style strerror_r() may set errno to ERANGE if insufficient
+  * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated
+  * message string, or EINVAL if 'errnum' is not a valid error number.
+  */
+  if(0 != strerror_r(err, buf, max)) {
+    if('\0' == buf[0])
+      snprintf(buf, max, "Unknown error %d", err);
+  }
+#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)
+ /*
+  * The glibc-style strerror_r() only *might* use the buffer we pass to
+  * the function, but it always returns the error message as a pointer,
+  * so we must copy that string unconditionally (if non-NULL).
+  */
   {
-    /* HAVE_GLIBC_STRERROR_R */
     char buffer[256];
     char *msg = strerror_r(err, buffer, sizeof(buffer));
-    /* this version of strerror_r() only *might* use the buffer we pass to
-       the function, but it always returns the error message as a pointer,
-       so we must copy that string unconditionally (if non-NULL) */
     if(msg)
       strncpy(buf, msg, max);
     else
       snprintf(buf, max, "Unknown error %d", err);
   }
-#endif /* end of HAVE_GLIBC_STRERROR_R */
-#else /* HAVE_STRERROR_R */
-  strncpy(buf, strerror(err), max);
-#endif /* end of HAVE_STRERROR_R */
+#else
+  {
+    char *msg = strerror(err);
+    if(msg)
+      strncpy(buf, msg, max);
+    else
+      snprintf(buf, max, "Unknown error %d", err);
+  }
+#endif
+
 #endif /* end of ! USE_WINSOCK */
 
   buf[max] = '\0'; /* make sure the string is zero terminated */
@@ -659,6 +660,10 @@ const char *Curl_strerror(struct connectdata *conn, int err)
      *p = '\0';
   if((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1)
      *p = '\0';
+
+  if(old_errno != ERRNO)
+    SET_ERRNO(old_errno);
+
   return buf;
 }
 
@@ -680,6 +685,7 @@ const char *Curl_idn_strerror (struct connectdata *conn, int err)
 
   buf = conn->syserr_buf;
   max = sizeof(conn->syserr_buf)-1;
+  *buf = '\0';
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   switch ((Idna_rc)err) {