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>