From: Eric Blake Date: Thu, 19 May 2011 19:35:39 +0000 (-0600) Subject: strerror_r: guarantee unchanged errno X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7f4877b4ad7eade913808e4b7a412e30be632bab;p=pspp strerror_r: guarantee unchanged errno POSIX guarantees that strerror doesn't change errno on success, and since we implement strerror by using strerror_r, it makes sense to make the same guarantee for strerror_r (rather, going one step further to say that sterror_r does not corrupt errno, since it returns an error value explicitly). See also http://austingroupbugs.net/view.php?id=447 * lib/strerror_r.c (strerror_r): Guarantee unchanged errno. * lib/strerror-impl.h (strerror): Set errno to match strerror_r failure. * tests/test-strerror_r.c (main): Enhance test. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index db41064127..49568395d7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2011-05-19 Eric Blake + + strerror_r: guarantee unchanged errno + * lib/strerror_r.c (strerror_r): Guarantee unchanged errno. + * lib/strerror-impl.h (strerror): Set errno to match strerror_r + failure. + * tests/test-strerror_r.c (main): Enhance test. + 2011-05-19 Bruno Haible strerror_r: Reorder #if blocks. diff --git a/lib/strerror-impl.h b/lib/strerror-impl.h index 6be2b2a8f3..a2042433cc 100644 --- a/lib/strerror-impl.h +++ b/lib/strerror-impl.h @@ -36,6 +36,7 @@ strerror (int n) static char const fmt[] = "Unknown error (%d)"; verify (sizeof (buf) >= sizeof (fmt) + INT_STRLEN_BOUND (n)); sprintf (buf, fmt, n); + errno = ret; return buf; } } diff --git a/lib/strerror_r.c b/lib/strerror_r.c index db48245106..4aac345424 100644 --- a/lib/strerror_r.c +++ b/lib/strerror_r.c @@ -403,21 +403,24 @@ strerror_r (int errnum, char *buf, size_t buflen) if (msg) { + int saved_errno = errno; size_t len = strlen (msg); + int ret = ERANGE; if (len < buflen) { memcpy (buf, msg, len + 1); - return 0; + ret = 0; } - else - return ERANGE; + errno = saved_errno; + return ret; } } #endif { int ret; + int saved_errno = errno; #if USE_XPG_STRERROR_R @@ -519,7 +522,6 @@ strerror_r (int errnum, char *buf, size_t buflen) if (errnum >= 0 && errnum < sys_nerr) { # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux) - int saved_errno = errno; # if defined __NetBSD__ nl_catd catd = catopen ("libc", NL_CAT_LOCALE); const char *errmsg = @@ -554,7 +556,6 @@ strerror_r (int errnum, char *buf, size_t buflen) # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux) if (catd != (nl_catd)-1) catclose (catd); - errno = saved_errno; # endif } else @@ -618,6 +619,7 @@ strerror_r (int errnum, char *buf, size_t buflen) #endif + errno = saved_errno; return ret; } } diff --git a/tests/test-strerror_r.c b/tests/test-strerror_r.c index 7aad3c7365..48287678bd 100644 --- a/tests/test-strerror_r.c +++ b/tests/test-strerror_r.c @@ -34,35 +34,45 @@ main (void) /* Test results with valid errnum and enough room. */ + errno = 0; buf[0] = '\0'; ASSERT (strerror_r (EACCES, buf, sizeof (buf)) == 0); ASSERT (buf[0] != '\0'); + ASSERT (errno == 0); + errno = 0; buf[0] = '\0'; ASSERT (strerror_r (ETIMEDOUT, buf, sizeof (buf)) == 0); ASSERT (buf[0] != '\0'); + ASSERT (errno == 0); + errno = 0; buf[0] = '\0'; ASSERT (strerror_r (EOVERFLOW, buf, sizeof (buf)) == 0); ASSERT (buf[0] != '\0'); + ASSERT (errno == 0); /* POSIX requires strerror (0) to succeed. Reject use of "Unknown error", but allow "Success", "No error", or even Solaris' "Error 0" which are distinct patterns from true out-of-range strings. http://austingroupbugs.net/view.php?id=382 */ + errno = 0; buf[0] = '\0'; ret = strerror_r (0, buf, sizeof (buf)); ASSERT (ret == 0); ASSERT (buf[0]); + ASSERT (errno == 0); ASSERT (strstr (buf, "nknown") == NULL); /* Test results with out-of-range errnum and enough room. */ + errno = 0; buf[0] = '^'; ret = strerror_r (-3, buf, sizeof (buf)); ASSERT (ret == 0 || ret == EINVAL); if (ret == 0) ASSERT (buf[0] != '^'); + ASSERT (errno == 0); /* Test results with a too small buffer. */ @@ -74,7 +84,9 @@ main (void) for (i = 0; i <= len; i++) { strcpy (buf, "BADFACE"); + errno = 0; ret = strerror_r (EACCES, buf, i); + ASSERT (errno == 0); if (ret == 0) { /* Truncated result. POSIX allows this, and it actually @@ -90,8 +102,10 @@ main (void) } strcpy (buf, "BADFACE"); + errno = 0; ret = strerror_r (EACCES, buf, len + 1); ASSERT (ret == 0); + ASSERT (errno == 0); } return 0;