mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-22 01:34:09 +00:00
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:
parent
1dfc179686
commit
5a98f074e6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=108044
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue