Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 14 Dec 2004 05:57:38 +1100
From:      Peter Jeremy <PeterJeremy@optushome.com.au>
To:        henry <henry@jot.to>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: du(1)/fts(3)  integer overflow
Message-ID:  <20041213185738.GD79646@cirb503493.alcatel.com.au>
In-Reply-To: <200412131142.iBDBgMp4082138@mail.squidge.com>
References:  <200412131142.iBDBgMp4082138@mail.squidge.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, 2004-Dec-13 11:42:17 -0000, henry wrote:
>I have noticed a problem with the fts(3) library or the way du(1) interacts
>with it.
>
>A 3.2TiB file gives the following output:
>> du -cs /fs/file
>3408720016      /fs/file
>-886247279      total
>
>This is because while stat(2) reports blocks as a 64bit number du(1) uses
>the 32bit value FTSENT.fts_number to store the result:

I think the large filesystem support is insufficiently exercised and
there will probably be more of these sort of things lurking around.

>The simplest change appears to be to make fts_number 64bit however this
>changes the fts(3) abi, so I am not sure if this is acceptable.

For 6.x, the ABI isn't fixed so fts_number can be changed to int64_t.
4.x doesn't really support large filesystems due to integer overflow
issues in UFS/FFS code so it's not really a problem there.

The 5.x ABI is fixed so there's no simple solution there.  Possible hacks
would be:
- Add a new 'fts_number64' at the end of FTSENT.  Since FTSENT is always
  managed by fts(3) and the documentation allows for undocumented fields,
  this should be permitted, though a "new" du(1) with an "old" libc
  would break badly.
- Move fts_number to the end of FTSENT and leave a 'long' hole where the
  existing fts_number is.  This changes the ABI but old programs remain
  compatible with the new fts.  (Though new programs break with the
  old fts).
- <Severe_kludge_alert>Have du(1) treat fts_pointer as an integer that
  it can concatenate to fts_number on 32-bit architectures:
    int64_t x = (int64_t)(ulong)p->fts_parent->fts_number |
	((int64_t)(ulong)p->fts_parent->fts_pointer) << 32;
    x += p->fts_statp->st_blocks;
    p->fts_parent->fts_number = (long)x;
    p->fts_parent->fts_pointer = (void *)(long)(x >> 32);
  etc. </Severe_kludge_alert>

-- 
Peter Jeremy



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