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
This commit is contained in:
Mike Barcroft 2002-12-18 16:53:31 +00:00
parent 1dfc179686
commit 5a98f074e6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=108044
2 changed files with 50 additions and 91 deletions

View file

@ -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

View file

@ -37,108 +37,62 @@ static char sccsid[] = "@(#)strerror.c 8.1 (Berkeley) 6/4/93";
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int
strerror_r(int errnum, char *strerrbuf, size_t buflen)
#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))
/* Don't link to stdio(3) to avoid bloat for statically linked binaries. */
static void
errstr(int num, char *buf, size_t len)
{
int len;
unsigned int uerr;
char *p, *t;
char tmp[EBUFSIZE];
if ((errnum >= 0) && (errnum < sys_nerr)) {
len = strlcpy(strerrbuf, (char *)sys_errlist[errnum], buflen);
return ((len < buflen) ? 0 : ERANGE);
}
return (EINVAL);
}
char *
strerror(num)
int num;
{
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]);
/*
* 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';
}
int
strerror_r(int errnum, char *strerrbuf, size_t buflen)
{
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);
}
char *
strerror(int num)
{
static char ebuf[EBUFSIZE];
if (num > 0 && num < sys_nerr)
return ((char *)sys_errlist[num]);
errno = EINVAL;
errstr(num, ebuf, sizeof(ebuf));
return (ebuf);
}
#ifdef STANDALONE_TEST
#include <limits.h>
main()
{
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);
memset(mybuf, '*', 63); mybuf[63] = '\0';
ret = strerror_r(1234, mybuf, 64);
printf("strerror_r(1234) returns %d (%s)\n", ret, mybuf);
memset(mybuf, '*', 63); mybuf[63] = '\0';
ret = strerror_r(1, mybuf, 10);
printf("strerror_r on short buffer returns %d (%s)\n", ret, mybuf);
}
#endif