This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
Linux getdents.c is not aliasing safe
- From: Daniel Jacobowitz <dan at debian dot org>
- To: libc-alpha at sources dot redhat dot com
- Cc: debian-glibc at lists dot debian dot org
- Date: Tue, 29 Oct 2002 16:58:03 -0500
- Subject: Linux getdents.c is not aliasing safe
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.
--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer