This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
Re: Linux getdents.c is not aliasing safe
- From: Andreas Schwab <schwab at suse dot de>
- To: libc-alpha at sources dot redhat dot com
- Cc: debian-glibc at lists dot debian dot org
- Date: Tue, 29 Oct 2002 23:33:49 +0100
- Subject: Re: Linux getdents.c is not aliasing safe
- References: <20021029215802.GA9479@nevyn.them.org>
Daniel Jacobowitz <dan@debian.org> writes:
|> Highlights:
|> char *kbuf = buf;
|> size_t kbytes = nbytes;
|> if (offsetof (DIRENT_TYPE, d_name)
|> < offsetof (struct kernel_dirent64, d_name)
|> && nbytes <= sizeof (DIRENT_TYPE))
|> {
|> kbytes = nbytes + offsetof (struct kernel_dirent64, d_name)
|> - offsetof (DIRENT_TYPE, d_name);
|> kbuf = __alloca(kbytes);
|> }
|>
|> dp = (DIRENT_TYPE *)buf;
|> kdp = (struct kernel_dirent64 *) kbuf;
|>
|> uint64_t d_ino = kdp->d_ino;
|> int64_t d_off = kdp->d_off;
|> unsigned char d_type = kdp->d_type;
|>
|> DIRENT_SET_DP_INO (dp, d_ino);
|> dp->d_off = d_off;
|>
|> GCC is perfectly free to re-order the stores and loads here; if it does,
|> when buf and kbuf are pointing at the same thing (which they usually are),
|> then storing to dp->d_off (at offset 4 in a 32-bit dirent) corrupts d_ino
|> (at offset 0 and size 8 in a kernel_dirent64). This is why Debian was
|> seeing a broken ldconfig.
|>
|> Not sure how to fix this while still editing the buffer in-place. It seems
|> like we want the equivalent of:
|>
|> union {
|> DIRENT_TYPE dpbuf[];
|> struct kernel_dirent64[];
|> }
|>
|> but that's not legal C.
How about using two pointers of type
union {
DIRENT_TYPE dp;
struct kernel_dirent64 kdp;
}
?
Andreas.
--
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux AG, Deutschherrnstr. 15-19, D-90429 Nürnberg
Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."