Date: Fri, 13 Dec 2002 12:58:16 -0500 From: Mike Barcroft <mike@FreeBSD.org> To: standards@FreeBSD.org Subject: strerror.diff and se-regress.shar for review Message-ID: <20021213125816.C61753@espresso.q9media.com> In-Reply-To: <20021213114038.A61753@espresso.q9media.com>; from mike@FreeBSD.org on Fri, Dec 13, 2002 at 11:40:38AM -0500 References: <20021213114038.A61753@espresso.q9media.com>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Attached is my patch to resolved PR 44356 (strerror.diff). I've also
taken the liberty of moving strerror()/strerror_r()'s regression tests
into src/tools/regression/lib/libc (se-regress.shar).
Comments appreciated.
Best regards,
Mike Barcroft
[-- Attachment #2 --]
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
Index: strerror.3
===================================================================
RCS file: /work/repo/src/lib/libc/string/strerror.3,v
retrieving revision 1.20
diff -u -r1.20 strerror.3
--- strerror.3 24 Oct 2002 01:24:26 -0000 1.20
+++ strerror.3 13 Dec 2002 16:45:51 -0000
@@ -115,7 +115,7 @@
unchanged and returns
.Er EINVAL .
Error numbers recognized by this implementation fall in
-the range 0 \(<=
+the range 0 \(<
.Fa errnum
<
.Fa sys_nerr .
@@ -168,6 +168,11 @@
.Fn strerror
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
Index: strerror.c
===================================================================
RCS file: /work/repo/src/lib/libc/string/strerror.c,v
retrieving revision 1.8
diff -u -r1.8 strerror.c
--- strerror.c 3 Jul 2002 06:28:04 -0000 1.8
+++ strerror.c 13 Dec 2002 17:23:14 -0000
@@ -37,108 +37,62 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/lib/libc/string/strerror.c,v 1.8 2002/07/03 06:28:04 mini Exp $");
+#include <errno.h>
#include <stdio.h>
#include <string.h>
-#include <errno.h>
-
-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);
-}
-
-char *
-strerror(num)
- int num;
+#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)
{
- 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;
+ unsigned int uerr;
+ char *p, *t;
+ char tmp[EBUFSIZE];
- /*
- * 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
+int
+strerror_r(int errnum, char *strerrbuf, size_t buflen)
+{
+ int retval;
-#include <limits.h>
+ 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);
+}
-main()
+char *
+strerror(int num)
{
- char mybuf[64];
- int ret;
-
- errno = 0;
+ static char ebuf[EBUFSIZE];
- 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);
+ if (num > 0 && num < sys_nerr)
+ return ((char *)sys_errlist[num]);
+ errno = EINVAL;
+ errstr(num, ebuf, sizeof(ebuf));
+ return (ebuf);
}
-#endif
[-- Attachment #3 --]
# Apply this in src/tools/regression/lib/libc
#
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# string
# string/Makefile
# string/test-strerror.c
#
echo c - string
mkdir -p string > /dev/null 2>&1
echo x - string/Makefile
sed 's/^X//' >string/Makefile << 'END-of-string/Makefile'
X# $FreeBSD$
X
XTESTS= test-strerror
X
X.PHONY: tests
Xtests: ${TESTS}
X for p in ${TESTS}; do ${.OBJDIR}/$$p; done
X
X.PHONY: clean
Xclean:
X -rm -f ${TESTS}
END-of-string/Makefile
echo x - string/test-strerror.c
sed 's/^X//' >string/test-strerror.c << 'END-of-string/test-strerror.c'
X/*-
X * Copyright (c) 2001 Wes Peters <wes@FreeBSD.org>
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X * notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X * notice, this list of conditions and the following disclaimer in the
X * documentation and/or other materials provided with the distribution.
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X *
X * $FreeBSD$
X */
X
X#include <assert.h>
X#include <errno.h>
X#include <limits.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X
Xint
Xmain(void)
X{
X char buf[64];
X char *sret;
X int iret;
X
X /*
X * strerror() failure tests.
X */
X errno = 0;
X sret = strerror(0);
X assert(strcmp(sret, "Unknown error: 0") == 0);
X assert(errno == EINVAL);
X
X errno = 0;
X sret = strerror(INT_MAX);
X snprintf(buf, sizeof(buf), "Unknown error: %d", INT_MAX);
X assert(strcmp(sret, buf) == 0);
X assert(errno == EINVAL);
X
X /*
X * strerror() success tests.
X */
X errno = 0;
X sret = strerror(EPERM);
X assert(strcmp(sret, "Operation not permitted") == 0);
X assert(errno == 0);
X
X errno = 0;
X sret = strerror(EPFNOSUPPORT);
X assert(strcmp(sret, "Protocol family not supported") == 0);
X assert(errno == 0);
X
X errno = 0;
X sret = strerror(ELAST);
X assert(errno == 0);
X
X printf("PASS strerror()\n");
X
X /*
X * strerror_r() failure tests.
X */
X memset(buf, '*', sizeof(buf));
X iret = strerror_r(0, buf, sizeof(buf));
X assert(strcmp(buf, "Unknown error: 0") == 0);
X assert(iret == EINVAL);
X
X memset(buf, '*', sizeof(buf));
X /* One byte too short. */
X iret = strerror_r(EPERM, buf, strlen("Operation not permitted"));
X assert(strcmp(buf, "Operation not permitte") == 0);
X assert(iret == ERANGE);
X
X memset(buf, '*', sizeof(buf));
X /* One byte too short. */
X iret = strerror_r(-1, buf, strlen("Unknown error: -1"));
X assert(strcmp(buf, "Unknown error: -") == 0);
X assert(iret == EINVAL);
X
X memset(buf, '*', sizeof(buf));
X /* Two bytes too short. */
X iret = strerror_r(-2, buf, strlen("Unknown error: -2") - 1);
X assert(strcmp(buf, "Unknown error: ") == 0);
X assert(iret == EINVAL);
X
X memset(buf, '*', sizeof(buf));
X /* Three bytes too short. */
X iret = strerror_r(-2, buf, strlen("Unknown error: -2") - 2);
X assert(strcmp(buf, "Unknown error:") == 0);
X assert(iret == EINVAL);
X
X memset(buf, '*', sizeof(buf));
X /* One byte too short. */
X iret = strerror_r(12345, buf, strlen("Unknown error: 12345"));
X assert(strcmp(buf, "Unknown error: 1234") == 0);
X assert(iret == EINVAL);
X
X /*
X * strerror_r() success tests.
X */
X memset(buf, '*', sizeof(buf));
X iret = strerror_r(EDEADLK, buf, sizeof(buf));
X assert(strcmp(buf, "Resource deadlock avoided") == 0);
X assert(iret == 0);
X
X memset(buf, '*', sizeof(buf));
X iret = strerror_r(EPROCLIM, buf, sizeof(buf));
X assert(strcmp(buf, "Too many processes") == 0);
X assert(iret == 0);
X
X printf("PASS strerror_r()\n");
X
X exit(0);
X}
END-of-string/test-strerror.c
exit
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20021213125816.C61753>
