Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Dec 2001 15:45:07 +0200
From:      Ruslan Ermilov <ru@FreeBSD.org>
To:        Andrey Chernov <ache@FreeBSD.org>, Guido van Rooij <guido@gvr.org>
Cc:        standards@FreeBSD.org
Subject:   Recent POSIX.1-2001 implementation of strtol(3) breaks POLA (was: Re: cvs commit: src/etc/periodic/security 550.ipfwlimit 650.ip6fwlimit)
Message-ID:  <20011214154506.A79266@sunbay.com>
In-Reply-To: <20011214142928.A69958@sunbay.com>
References:  <200112140858.fBE8wL596075@freefall.freebsd.org> <20011214115711.A34932@gvr.gvr.org> <20011214135243.B64853@sunbay.com> <20011214125438.A35615@gvr.gvr.org> <20011214142928.A69958@sunbay.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, Dec 14, 2001 at 02:29:28PM +0200, Ruslan Ermilov wrote:
> On Fri, Dec 14, 2001 at 12:54:38PM +0100, Guido van Rooij wrote:
> > On Fri, Dec 14, 2001 at 01:52:43PM +0200, Ruslan Ermilov wrote:
> > > On Fri, Dec 14, 2001 at 11:57:11AM +0100, Guido van Rooij wrote:
> > > > On Fri, Dec 14, 2001 at 12:58:21AM -0800, Ruslan Ermilov wrote:
> > > > > ru          2001/12/14 00:58:21 PST
> > > > > 
> > > > >   Modified files:
> > > > >     etc/periodic/security 550.ipfwlimit 650.ip6fwlimit 
> > > > >   Log:
> > > > >   Work around the bugfeature of test(1).
> > > > >   
> > > > >   PR:             bin/32822
> > > > 
> > > > 
> > > > If I run this:
> > > > if [ 0 -eq 0 -a "" -ne 1 ];
> > > > 	then echo foo
> > > > fi
> > > > then it works. Isn't the real problem that "${IPFW_LOG_LIMIT}" gets lost
> > > > somehow?
> > > > 
> > > Nope, try this:
> > > 
> > > FOO=
> > > if [ 0 -eq 1 -a ${FOO} -ne 1 ]; then
> > > 	echo OK
> > > fi
> > > 
> > > An alternate solution would be to write:
> > > 
> > > if [ 0 -eq 1 -a "${FOO}" -ne 1 ]; then
> > 
> > But that is what was in /etc/security.. So why did it fail?
> > 
> Now I feel really confused.  I could reproduce this at the
> morning, but couldn't after reading your mail.  Fortunately,
> I've figured what's different:
> 
> $ /STABLE/bin/[ "" -eq 0 ]
> $ /CURRENT/bin/[ "" -eq 0 ]
> [: : out of range
> 
> I'll investigate what's wrong with -current's /bin/[ shortly
> and will back my (not actually relevant) changes out.
> 
The actual difference turned out to be in strtol(3), not test(1).
The following program demonstrates the difference:

#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

int
main(void)
{
	const char *s = "";
	char *p;

	errno = 0;
	(void) strtol(s, &p, 10);
	if (errno != 0)
		errx(1, "%s: out of range", s);
	exit(0);
}

In -CURRENT, Andrey Chernov recently committed his POSIX.1-2001
compliant version of strtol().  POSIX, in particular, says
about strtol() and strtoll():

: First, they decompose the input string into three parts:
: 
: 1. An initial, possibly empty, sequence of white-space characters
: (as specified by isspace())
: 
: 2. A subject sequence interpreted as an integer represented in some
: radix determined by the value of base
: 
: 3. A final string of one or more unrecognized characters, including
: the terminating null byte of the input string.

And then:

: If the subject sequence is empty or does not have the expected form,
: no conversion is performed; the value of str is stored in the
  ^^^^^^^^^^^^^^^^^^^^^^^^^^
: object pointed to by endptr, provided t hat endptr is not a null
: pointer.  The strtol() function shall not change the setting of errno
: if successful.

And later:

: Upon successful completion, these functions shall return the converted
: value, if any. If no conversion could be performed, 0 shall be
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
: returned and errno may be set to [EINVAL].
                     ^^^^^^^^^^^^^^^^^^^^^^

So, it seems that the "empty subject sequence" case falls under the
"if no conversion could be performed" case, and strtol() MAY set
errno to [EINVAL].

Well, I've tested the behavior of strtol() in regards to this on
NetBSD, OpenBSD, UnixWare, and Linux.

In NetBSD and OpenBSD, strtol() doesn't set errno to EINVAL if the
subject is empty.  In UnixWare, it does, but atoi(3), which is
implemented there using strtol() too, has a special hack to not
set errno to EINVAL in this case, and this is a documented
behavior.

Linux's strtol() doesn't set errno to EINVAL too, but their
test(1) utility works like this:

$ /usr/bin/test "" -eq 0
/usr/bin/test: integer expression expected before -eq

What's really broken in FreeBSD now is that the following:

  errno = 0;
  atoi("");

sets errno to [EINVAL], while it shouldn't.  I think this
may break many things.

So while the current behavior of strtol() is accepted by
POSIX, I suggest that we don't return [EINVAL] for an
empty subject case, as it's not required, and as could
be seen from the above in against POLA.  This should
fix it.

--- /usr/src/lib/libc/stdlib/strtol.c	Mon Dec 10 10:36:35 2001
+++ strtol.c	Fri Dec 14 15:40:23 2001
@@ -87,8 +87,10 @@ strtol(nptr, endptr, base)
 	if (base == 0)
 		base = c == '0' ? 8 : 10;
 	acc = any = 0;
-	if (base < 2 || base > 36)
+	if (base < 2 || base > 36) {
+		errno = EINVAL;
 		goto noconv;
+	}
 
 	/*
 	 * Compute the cutoff value between legal numbers and illegal
@@ -133,11 +135,9 @@ strtol(nptr, endptr, base)
 	if (any < 0) {
 		acc = neg ? LONG_MIN : LONG_MAX;
 		errno = ERANGE;
-	} else if (!any) {
-noconv:
-		errno = EINVAL;
-	} else if (neg)
+	} else if (any > 0 && neg)
 		acc = -acc;
+noconv:
 	if (endptr != NULL)
 		*endptr = (char *)(any ? s - 1 : nptr);
 	return (acc);


Cheers,
-- 
Ruslan Ermilov		Oracle Developer/DBA,
ru@sunbay.com		Sunbay Software AG,
ru@FreeBSD.org		FreeBSD committer,
+380.652.512.251	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe cvs-all" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20011214154506.A79266>