bin/142911: [patch] vmstat(8) -w should produce error message
if fed a negative value
brde at optusnet.com.au
Tue Jan 19 14:10:10 UTC 2010
The following reply was made to PR bin/142911; it has been noted by GNATS.
From: Bruce Evans <brde at optusnet.com.au>
To: Efstratios Karatzas <gpf.kira at gmail.com>
Cc: bug-followup at FreeBSD.org, Bruce Evans <brde at optusnet.com.au>
Subject: Re: bin/142911: [patch] vmstat(8) -w should produce error message
if fed a negative value
Date: Wed, 20 Jan 2010 01:04:37 +1100 (EST)
On Mon, 18 Jan 2010, Efstratios Karatzas wrote:
> I still can't understand why would anyone use "vmstat 0" or "vmstat -w 0".
> It's the same output if you just use "vmstat".
> I am aware of the BACKWARD_COMPATIBILITY behavior but negative values
> don't work with it, for example "vmstat -3" produces an illegal option error.
That accidentally avoids the int -> unsigned conversion error.
However, there is another conversion here, not fixed by your version:
strtol() returns long, so on 64-bit arches, since long is actually long,
it is longer than int, so when atoi blindly converts the value to int
it gets truncated to a garbage value if the correct value is > INT_MAX.
2**31 becomes -2**31 (accidentally handled as error, with confusing
error message about the arg being < 1)
2**32 becomes 0 (accidentally...)
2**32+1 becomes 1 (error not detected)
2**63 first becomes LONG_MAX (2**63-1) with error ERANGE in strtol()
becomes 2**31-1 (error not detected)
> 2**63: same as 2**63.
-2**31 stays as -2**31
-2**32 becomes 0
-2**32+1 becomes 1
>= 2**-63 first becomes LONG_MIN, then INT_MIN (error detected).
The large values are not useful so they shouldn't be used, but the same is
true for negative values.
> Although "vmstat abc" will work just fine but it is not much of a problem.
> We could perform a more "sophisticated" error check.
> A call to atoi(3) is actually a call to strtol(3).
> strtol(3) will return 0 and set errno to EINVAL if no conversion could be
> eg "vmstat -w abc"
> So we could check the value of errno when atoi() returns 0.
After setting errno to != EINVAL before the call.
> But the man page states that this feature is not portable across all platforms!
This is not even portable to POSIX systems. On POSIX systems, the POSIX is
also undefined on overflow. Other errors are only implementation-defined.
This depends on the behaviour being the same as casting strtol() to int,
as documented, and on strtol() having a new misfeature in POSIX (that
errno is clobbered to EINVAL for some but not all types of parsing
This behaviour should never be depended on. Just use strtol() with
normal error checking (check that the end pointer has advanced and
doesn't point to garbage). errno doesn't need to be checked for this.
However, errno needs to be set to != ERANGE before the call and checked
== ERANGE after the call to check for range errors. Then the result
must be checked to fit in the int or unsigned variable.
FreeBSD has 2 nonstandard badly designed interfaces that are intended
to be easier to use than strto*() and atoi(): strtonum() and
expand_number(). Their bad design starts with then not supporting
intmax_t, uintmax_t or any floating point type. strtonum() doesn't
even support unsigned longs on 64-bit arches, and it uses the long
long abomination. But it is an adequate replacement for strtol(),
and thus OK for replacing atoi() in most command option parsing.
Another issue is whether numeric command options should be limited to
decimal values representable as a long or even as an int. I think they
shouldn't have any arbitrary limits, but POSIX may over-specify them as
being decimal and/or of limited size. Another design bug in strtonum()
is that it only supports decimal numbers. This makes it more compatible
with atoi() but less useful than it should be.
More information about the freebsd-bugs