Date: Tue, 04 Dec 2001 10:36:21 -0700 From: Wes Peters <wes@softweyr.com> To: Bruce Evans <bde@zeta.org.au> Cc: Garance A Drosihn <drosih@rpi.edu>, Bill Fenner <fenner@research.att.com>, mike@FreeBSD.org, freebsd-standards@bostonradio.org Subject: Re: strerror_r() implementation Message-ID: <3C0D0995.A7FEFB47@softweyr.com> References: <20011203005459.N8502-100000@gamplex.bde.org>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------3F65B277ABF926BCC3633994 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Bruce Evans wrote: > > On Sat, 1 Dec 2001, Garance A Drosihn wrote: > > > At 1:52 AM +1100 12/2/01, Bruce Evans wrote: > > > > > (1) missing parens around return values > > >> > > >> style(9) remains silent on this subject. Until required to do so by > > > > > >It is not silent, but not very verbose. All of the examples of returning > > >a value in style(9) use "return (foo)". There is a whole one such example. > > >It apparently didn't occur to the origianal author of style(9) that this > > >needed an explicit rule. > > > > In the argumentative half of my message (this here message...), I will note > > that style(9) also says that parenthesis should not be added unless they are > > necessary, and previous discussions have indicated that parentheses are not > > in fact necessary in C on return statements... The more I have thought > > Individual rules have precedence over general ones. That would be fine, if there were indeed an individual rule. Please feel free to commit one at any time. > > >I tested it a bit more and found a bug in the test code: the test of a > > >short buffer returns an unterminated string (as expected), and printing > > >this non-string using %s gives garbage. > > > > Hmm. I do not have the standards document for strerror_r(), but I am > > surprised that a short buffer is expected to return a string which is > > not null-terminated. Note that I am not arguing the point, I'm just > > surprised. That means all callers to strerror_r() should never treat > > the result as a null-terminated string, even though it usually will > > be null-terminated. Seems to me that is asking for trouble. > > I think the contents of the buffer is indeterminate when strerror_r() > fails. POSIX-1.200x-draft7 is not completely clear on this. The POSIX specificaion Mike mailed to me said "indeterminate". Not nul-terminated seems consistent with "indeterminate", and is documented as so in the man page. > strerror_r() is also permitted to fail if the error number is invalid. > It must then return EINVAL. So the conversion to ASCII is not needed > for strerror_r(), and it may be considered a bug that strerror_r() > doesn't fail for bogus error numbers. However, the conversion is > needed for strerror(). Which leads to an interested conundrum about what "invalid" might be. Is an errno not in the system list "invalid" or just "not predefined?" Does the POSIX specification lead us off this slippery slope, or should the handling of errnos >= sys_nerr be moved to strerror? > Here is my current version of the cleanups for strerror(). New changes: > - don't resever bogus extra space for UPREFIX in ebuf[]. > - fix breakage of reentrancy of strerror_r() in previous verions (tmp[] > must be auto). But this one seems to be dependent on the non-conforming behavior of strerror_r you have noted. I have attached a rewritten version in which strerror_r returns a message only for "known" errors, otherwise it returns EINVAL. The "unknown" message rendering code has been returned to strerror. The number buffer has been sized appropriately at 21 characters, and the static buffer is just long enough to hold the "Unknown error: " message plus the number. I have even obfuscated all returns with unnecessary ()s for Bruce. strerror is no longer implemented in terms of strerror_r since the requirements are so divergent. Please review at your leisure. Once we agree this is "good enough" I'll commit it. I'd prefer to be able to MFC this before the 4.5 freeze. Could one of you standards guys provide a standards compliance statement for the man page? -- "Where am I, and what am I doing in this handbasket?" Wes Peters Softweyr LLC wes@softweyr.com http://softweyr.com/ --------------3F65B277ABF926BCC3633994 Content-Type: text/plain; charset=us-ascii; name="strerror.3" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="strerror.3" .\" Copyright (c) 1980, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" This code is derived from software contributed to Berkeley by .\" the American National Standards Committee X3, on Information .\" Processing Systems. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)strerror.3 8.1 (Berkeley) 6/9/93 .\" $FreeBSD: src/lib/libc/string/strerror.3,v 1.7.2.4 2001/08/17 15:42:43 ru Exp $ .\" .Dd Nov 26, 2001 .Dt STRERROR 3 .Os .Sh NAME .Nm perror , .Nm strerror , .Nm strerror_r , .Nm sys_errlist , .Nm sys_nerr .Nd system error messages .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In stdio.h .Ft void .Fn perror "const char *string" .Vt extern const char * const sys_errlist[] ; .Vt extern const int sys_nerr ; .In string.h .Ft char * .Fn strerror "int errnum" .Ft int .Fn strerror_r "int errnum" "char * strerrbuf" "size_t buflen" .Sh DESCRIPTION The .Fn strerror , .Fn strerror_r and .Fn perror functions look up the error message string corresponding to an error number. .Pp The .Fn strerror function accepts an error number argument .Fa errnum and returns a pointer to the corresponding message string. .Pp The .Fn strerror_r function renders the same result into .Fa strerrbuf for a maximum of .Fa buflen characters and returns 0 upon success. .Pp The .Fn perror function finds the error message corresponding to the current value of the global variable .Va errno .Pq Xr intro 2 and writes it, followed by a newline, to the standard error file descriptor. If the argument .Fa string is .Pf non- Dv NULL and does not point to the null character, this string is prepended to the message string and separated from it by a colon and space .Pq Ql \&:\ \& ; otherwise, only the error message string is printed. .Pp If .Fa errnum is not a recognized error number, .Fn strerror returns an error message string containing .Dq Li "Unknown error:\ " followed by the error number in decimal, while .Fn strerror_r returns .Er EINVAL . .Pp If insufficient storage is provided in .Fa strerrbuf (as specified in .Fa buflen ) to contain the error string, .Fn strerror_r returns .Er ERANGE and the contents of .Fa strerrbuf are indeterminate. .Pp The message strings can be accessed directly using the external array .Va sys_errlist . The external value .Va sys_nerr contains a count of the messages in .Va sys_errlist . The use of these variables is deprecated; .Fn strerror or .Fn strerror_r should be used instead. .Sh SEE ALSO .Xr intro 2 , .Xr psignal 3 .Sh HISTORY The .Fn strerror and .Fn perror functions first appeared in .Bx 4.4 . The .Fn strerror_r function was implemented in .Fx 4.4 by .An Wes Peters .Aq wes@freebsd.org . .Sh BUGS For unknown error numbers, the .Fn strerror function will return its result in a static buffer which may be overwritten by subsequent calls. .Pp Programs that use the deprecated .Va sys_errlist variable often fail to compile because they declare it inconsistently. --------------3F65B277ABF926BCC3633994 Content-Type: text/plain; charset=us-ascii; name="strerror.c" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="strerror.c" /* * Copyright (c) 1988, 1993 The Regents of the University of California. All * rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. 3. All advertising * materials mentioning features or use of this software must display the * following acknowledgement: This product includes software developed by the * University of California, Berkeley and its contributors. 4. Neither the * name of the University nor the names of its contributors may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)strerror.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #ifndef lint static const char rcsid[] = "$FreeBSD: src/lib/libc/string/strerror.c,v 1.2.14.1 2001/07/09 23:30:06 obrien Exp $"; #endif #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; { 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]); /* * 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; t = tmp; 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; ) *p++ = *--t; *p = '\0'; return (ebuf); } #ifdef STANDALONE_TEST #include <limits.h> main() { char mybuf[64]; int ret; printf("strerror(47) yeilds: %s\n", strerror(47)); printf("strerror(437) yeilds: %s\n", strerror(437)); 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 --------------3F65B277ABF926BCC3633994-- 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?3C0D0995.A7FEFB47>