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
--cWoXeonUoKmBZSoM Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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 --cWoXeonUoKmBZSoM Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="strerror.diff" 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 --cWoXeonUoKmBZSoM Content-Type: application/x-shar Content-Disposition: attachment; filename="se-regress.shar" # 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 --cWoXeonUoKmBZSoM-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-standards" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20021213125816.C61753>