From 91ae3fa45da5b963b386ec2315195c8a46fca992 Mon Sep 17 00:00:00 2001 From: mike Date: Wed, 18 Dec 2002 16:53:31 +0000 Subject: Rearrange strerror() so that its itoa procedure can be used with strerror_r(). Doing this allows us to ensure that strerror_r() always fills the supplied buffer regardless of EINVAL or ERANGE errors. strerror()'s semantics have changed slightly such that an argument of 0 is now considered invalid and errno is set to EINVAL. Remove internal regression test for strerror() and strerror_r(). This will be reincarnated in src/tools/regression/lib/libc/string. In strerror(3), add a comment about strerror()'s bogus return type. PR: 44356 --- lib/libc/string/strerror.3 | 7 ++- lib/libc/string/strerror.c | 124 ++++++++++++++------------------------------- 2 files changed, 45 insertions(+), 86 deletions(-) (limited to 'lib') diff --git a/lib/libc/string/strerror.3 b/lib/libc/string/strerror.3 index 93ed9b2..8a840e8 100644 --- a/lib/libc/string/strerror.3 +++ b/lib/libc/string/strerror.3 @@ -115,7 +115,7 @@ leaves unchanged and returns .Er EINVAL . Error numbers recognized by this implementation fall in -the range 0 \(<= +the range 0 \(< .Fa errnum < .Fa sys_nerr . @@ -169,6 +169,11 @@ For unknown error numbers, the function will return its result in a static buffer which may be overwritten by subsequent calls. .Pp +The return type for +.Fn strerror +is missing a type-qualifier; it should actually be +.Vt const char * . +.Pp The .Fn perror function is implemented in terms of diff --git a/lib/libc/string/strerror.c b/lib/libc/string/strerror.c index 32e35aa..0d2e126 100644 --- a/lib/libc/string/strerror.c +++ b/lib/libc/string/strerror.c @@ -37,108 +37,62 @@ static char sccsid[] = "@(#)strerror.c 8.1 (Berkeley) 6/4/93"; #include __FBSDID("$FreeBSD$"); +#include #include #include -#include -int -strerror_r(int errnum, char *strerrbuf, size_t buflen) -{ - int len; - - if ((errnum >= 0) && (errnum < sys_nerr)) { - len = strlcpy(strerrbuf, (char *)sys_errlist[errnum], buflen); - return ((len < buflen) ? 0 : ERANGE); - } - return (EINVAL); -} +#define UPREFIX "Unknown error: " +/* + * Define a buffer size big enough to describe a 64-bit signed integer + * converted to ASCII decimal (19 bytes), with an optional leading sign + * (1 byte), finally we get the prefix and a trailing NUL from UPREFIX. + */ +#define EBUFSIZE (20 + sizeof(UPREFIX)) -char * -strerror(num) - int num; +/* Don't link to stdio(3) to avoid bloat for statically linked binaries. */ +static void +errstr(int num, char *buf, size_t len) { - char *p, *t; - unsigned int uerr; - static char const unknown_prefix[] = "Unknown error: "; - - /* - * Define a buffer size big enough to describe a 64-bit - * number in ASCII decimal (19), with optional leading sign - * (+1) and trailing NUL (+1). - */ -# define NUMLEN 21 -# define EBUFLEN (sizeof unknown_prefix + NUMLEN) - char tmp[NUMLEN]; /* temporary number */ - static char ebuf[EBUFLEN]; /* error message */ - - if ((num >= 0) && (num < sys_nerr)) - return ((char *)sys_errlist[num]); + unsigned int uerr; + char *p, *t; + char tmp[EBUFSIZE]; - /* - * Set errno to EINVAL per P1003.1-200x Draft June 14, 2001. - */ - errno = EINVAL; - - /* - * Print unknown errno by hand so we don't link to stdio(3). - * This collects the ASCII digits in reverse order. - */ - uerr = (num > 0) ? num : -num; + if (strlcpy(buf, UPREFIX, len) >= len) + return; t = tmp; + uerr = (num >= 0) ? num : -num; do { *t++ = "0123456789"[uerr % 10]; } while (uerr /= 10); if (num < 0) *t++ = '-'; - - /* - * Copy the "unknown" message and the number into the caller - * supplied buffer, inverting the number string. - */ - strcpy(ebuf, unknown_prefix); - for (p = ebuf + sizeof unknown_prefix - 1; t > tmp; ) + for (p = buf + strlen(UPREFIX); t > tmp && p < buf + len - 1;) *p++ = *--t; *p = '\0'; - return (ebuf); } -#ifdef STANDALONE_TEST - -#include - -main() +int +strerror_r(int errnum, char *strerrbuf, size_t buflen) { - char mybuf[64]; - int ret; - - errno = 0; - - printf("strerror(0) yeilds: %s\n", strerror(0)); - printf("strerror(1) yeilds: %s\n", strerror(1)); - printf("strerror(47) yeilds: %s\n", strerror(47)); - printf("strerror(sys_nerr - 1) yeilds: %s\n", strerror(sys_nerr - 1)); - printf("errno = %d\n", errno); errno = 0; - - printf("strerror(sys_nerr) yeilds: %s\n", strerror(sys_nerr)); - printf("errno = %d\n", errno); errno = 0; - - printf("strerror(437) yeilds: %s\n", strerror(437)); - printf("errno = %d\n", errno); errno = 0; - - printf("strerror(LONG_MAX) yeilds: %s\n", strerror(LONG_MAX)); - printf("strerror(LONG_MIN) yeilds: %s\n", strerror(LONG_MIN)); - printf("strerror(ULONG_MAX) yeilds: %s\n", strerror(ULONG_MAX)); - - memset(mybuf, '*', 63); mybuf[63] = '\0'; - strerror_r(11, mybuf, 64); - printf("strerror_r(11) yeilds: %s\n", mybuf); + int retval; + + retval = 0; + if (errnum < 1 || errnum >= sys_nerr) { + errstr(errnum, strerrbuf, buflen); + retval = EINVAL; + } else if (strlcpy(strerrbuf, sys_errlist[errnum], buflen) >= buflen) + retval = ERANGE; + return (retval); +} - memset(mybuf, '*', 63); mybuf[63] = '\0'; - ret = strerror_r(1234, mybuf, 64); - printf("strerror_r(1234) returns %d (%s)\n", ret, mybuf); +char * +strerror(int num) +{ + static char ebuf[EBUFSIZE]; - memset(mybuf, '*', 63); mybuf[63] = '\0'; - ret = strerror_r(1, mybuf, 10); - printf("strerror_r on short buffer returns %d (%s)\n", ret, mybuf); + if (num > 0 && num < sys_nerr) + return ((char *)sys_errlist[num]); + errno = EINVAL; + errstr(num, ebuf, sizeof(ebuf)); + return (ebuf); } -#endif -- cgit v1.1