Skip site navigation (1)Skip section navigation (2)
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>