bin/62536: df gives insane numbers when using root-reserved space

Bruce Evans bde at zeta.org.au
Sat Mar 6 02:32:10 PST 2004


On Sat, 6 Mar 2004, Lukas Ertl wrote:

> On Sat, 6 Mar 2004, Kris Kennaway wrote:
>
> > On Fri, Mar 05, 2004 at 07:48:48AM -0800, Lukas Ertl wrote:
> > > Synopsis: df gives insane numbers when using root-reserved space
> > > ..
> > > Responsible-Changed-Why:
> > > I probably have a fix for this.
> >
> > pjd has a patch for this as well..I haven't yet tested it.

I discussed this bug with Ian Dowse.  As pointed out in my review of the
statfs changes, using unsigned types just asks for bugs like this.  What
chance has the average consumer of statfs avoiding these bugs when its
primary consumer (df) gets almost related to the larger sizes and signed
types wrong despite being adjusted for the statfs changes?

> Index: bin/df/df.c
> ===================================================================
> RCS file: /home/ncvs/src/bin/df/df.c,v
> retrieving revision 1.55
> diff -u -r1.55 df.c
> --- bin/df/df.c	5 Mar 2004 08:10:16 -0000	1.55
> +++ bin/df/df.c	5 Mar 2004 15:51:00 -0000
> @@ -400,7 +400,8 @@
>   */
>  #define fsbtoblk(num, fsbs, bs) \
>  	(((fsbs) != 0 && (fsbs) < (bs)) ? \
> -		(num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs)))
> +		(num) / (int64_t)((bs) / (fsbs)) : \
> +		(num) * (int64_t)((fsbs) / (bs)))
>
>  /*

I use this with intmax_t instead of int64_t.  Such casts are bogus, however,
Block sizes are now (bogusly) unsigned, and sometimes 64 bits too.  Casts
like the above only work if the the original types really are bogus.  If
all the bits of uint64_t were actually needed to hold block sizes, then the
casts would just truncate the values.  The truncation is done blindly.

Also, the point of the two cases in the above expression was to optimize
to avoid 64-bit arithmetic.  Now 64-bit arithmetic is unavoidable (the
compiler can't even optimize the division of block sizes since block
sizes are bogusly 640-bit), and the optimization is a pessimization.
Now we can just multiply the number of blocks by the block size provided
we don't do it blindly.  The result is sure to fit in an off_t unless
one of the operands is invalid, and an off_t is sure to fit in an intmax_t
if not in an int64_t.  Then the above macro is just:

	#define	fsbtoblk(num, fsbs, bs)	((intmax_t)(num) * (fsbs) / (bs))

modulo sanity checks and sign extension bugs.

Bruce


More information about the freebsd-bugs mailing list