Mercurial > hg > octave-lojdl > gnulib-hg
changeset 14769:8e815ef27998
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 <eblake@redhat.com>
author | Eric Blake <eblake@redhat.com> |
---|---|
date | Thu, 19 May 2011 13:35:39 -0600 |
parents | a12deda870d9 |
children | edc214f40f31 |
files | ChangeLog lib/strerror-impl.h lib/strerror_r.c tests/test-strerror_r.c |
diffstat | 4 files changed, 30 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2011-05-19 Eric Blake <eblake@redhat.com> + + 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 <bruno@clisp.org> strerror_r: Reorder #if blocks.
--- a/lib/strerror-impl.h +++ b/lib/strerror-impl.h @@ -36,6 +36,7 @@ static char const fmt[] = "Unknown error (%d)"; verify (sizeof (buf) >= sizeof (fmt) + INT_STRLEN_BOUND (n)); sprintf (buf, fmt, n); + errno = ret; return buf; } }
--- a/lib/strerror_r.c +++ b/lib/strerror_r.c @@ -403,21 +403,24 @@ 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 @@ 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 @@ # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux) if (catd != (nl_catd)-1) catclose (catd); - errno = saved_errno; # endif } else @@ -618,6 +619,7 @@ #endif + errno = saved_errno; return ret; } }
--- a/tests/test-strerror_r.c +++ b/tests/test-strerror_r.c @@ -34,35 +34,45 @@ /* 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 @@ 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 @@ } strcpy (buf, "BADFACE"); + errno = 0; ret = strerror_r (EACCES, buf, len + 1); ASSERT (ret == 0); + ASSERT (errno == 0); } return 0;