mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-30 22:43:12 +03:00
* sysdeps/unix/sysv/linux/getdents.c (__GETDENTS): Use union type for
pointers that can alias. Reported by Daniel Jacobowitz <drow@mvista.com>.
This commit is contained in:
@ -1,5 +1,9 @@
|
|||||||
2002-11-02 Roland McGrath <roland@redhat.com>
|
2002-11-02 Roland McGrath <roland@redhat.com>
|
||||||
|
|
||||||
|
* sysdeps/unix/sysv/linux/getdents.c (__GETDENTS): Use union type for
|
||||||
|
pointers that can alias.
|
||||||
|
Reported by Daniel Jacobowitz <drow@mvista.com>.
|
||||||
|
|
||||||
* sysdeps/unix/bsd/bsd4.4/freebsd/bits/typesizes.h: New file.
|
* sysdeps/unix/bsd/bsd4.4/freebsd/bits/typesizes.h: New file.
|
||||||
|
|
||||||
2002-11-02 Roland McGrath <roland@redhat.com>
|
2002-11-02 Roland McGrath <roland@redhat.com>
|
||||||
|
@ -97,7 +97,6 @@ ssize_t
|
|||||||
internal_function
|
internal_function
|
||||||
__GETDENTS (int fd, char *buf, size_t nbytes)
|
__GETDENTS (int fd, char *buf, size_t nbytes)
|
||||||
{
|
{
|
||||||
DIRENT_TYPE *dp;
|
|
||||||
off64_t last_offset = -1;
|
off64_t last_offset = -1;
|
||||||
ssize_t retval;
|
ssize_t retval;
|
||||||
|
|
||||||
@ -109,7 +108,12 @@ __GETDENTS (int fd, char *buf, size_t nbytes)
|
|||||||
# ifndef __ASSUME_GETDENTS64_SYSCALL
|
# ifndef __ASSUME_GETDENTS64_SYSCALL
|
||||||
int saved_errno = errno;
|
int saved_errno = errno;
|
||||||
# endif
|
# endif
|
||||||
char *kbuf = buf;
|
union
|
||||||
|
{
|
||||||
|
struct kernel_dirent64 k;
|
||||||
|
DIRENT_TYPE u;
|
||||||
|
char b[1];
|
||||||
|
} *kbuf = (void *) buf, *outp, *inp;
|
||||||
size_t kbytes = nbytes;
|
size_t kbytes = nbytes;
|
||||||
if (offsetof (DIRENT_TYPE, d_name)
|
if (offsetof (DIRENT_TYPE, d_name)
|
||||||
< offsetof (struct kernel_dirent64, d_name)
|
< offsetof (struct kernel_dirent64, d_name)
|
||||||
@ -125,7 +129,6 @@ __GETDENTS (int fd, char *buf, size_t nbytes)
|
|||||||
if (retval != -1 && errno != -EINVAL)
|
if (retval != -1 && errno != -EINVAL)
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
struct kernel_dirent64 *kdp;
|
|
||||||
const size_t size_diff = (offsetof (struct kernel_dirent64, d_name)
|
const size_t size_diff = (offsetof (struct kernel_dirent64, d_name)
|
||||||
- offsetof (DIRENT_TYPE, d_name));
|
- offsetof (DIRENT_TYPE, d_name));
|
||||||
|
|
||||||
@ -137,31 +140,43 @@ __GETDENTS (int fd, char *buf, size_t nbytes)
|
|||||||
need, don't do any conversions. */
|
need, don't do any conversions. */
|
||||||
if (offsetof (DIRENT_TYPE, d_name)
|
if (offsetof (DIRENT_TYPE, d_name)
|
||||||
== offsetof (struct kernel_dirent64, d_name)
|
== offsetof (struct kernel_dirent64, d_name)
|
||||||
&& sizeof (dp->d_ino) == sizeof (kdp->d_ino)
|
&& sizeof (outp->u.d_ino) == sizeof (inp->k.d_ino)
|
||||||
&& sizeof (dp->d_off) == sizeof (kdp->d_off))
|
&& sizeof (outp->u.d_off) == sizeof (inp->k.d_off))
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
dp = (DIRENT_TYPE *)buf;
|
/* These two pointers might alias the same memory buffer.
|
||||||
kdp = (struct kernel_dirent64 *) kbuf;
|
Standard C requires that we always use the same type for them,
|
||||||
while ((char *) kdp < kbuf + retval)
|
so we must use the union type. */
|
||||||
|
inp = kbuf;
|
||||||
|
outp = (void *) buf;
|
||||||
|
|
||||||
|
while (&inp->b < &kbuf->b + retval)
|
||||||
{
|
{
|
||||||
const size_t alignment = __alignof__ (DIRENT_TYPE);
|
const size_t alignment = __alignof__ (DIRENT_TYPE);
|
||||||
/* Since kdp->d_reclen is already aligned for the kernel
|
/* Since inp->k.d_reclen is already aligned for the kernel
|
||||||
structure this may compute a value that is bigger
|
structure this may compute a value that is bigger
|
||||||
than necessary. */
|
than necessary. */
|
||||||
size_t old_reclen = kdp->d_reclen;
|
size_t old_reclen = inp->k.d_reclen;
|
||||||
size_t new_reclen = ((old_reclen - size_diff + alignment - 1)
|
size_t new_reclen = ((old_reclen - size_diff + alignment - 1)
|
||||||
& ~(alignment - 1));
|
& ~(alignment - 1));
|
||||||
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);
|
/* Copy the data out of the old structure into temporary space.
|
||||||
dp->d_off = d_off;
|
Then copy the name, which may overlap if BUF == KBUF. */
|
||||||
if ((sizeof (dp->d_ino) != sizeof (kdp->d_ino)
|
const uint64_t d_ino = inp->k.d_ino;
|
||||||
&& dp->d_ino != d_ino)
|
const int64_t d_off = inp->k.d_off;
|
||||||
|| (sizeof (dp->d_off) != sizeof (kdp->d_off)
|
const uint8_t d_type = inp->k.d_type;
|
||||||
&& dp->d_off != d_off))
|
|
||||||
|
memmove (outp->u.d_name, inp->k.d_name,
|
||||||
|
old_reclen - offsetof (struct kernel_dirent64, d_name));
|
||||||
|
|
||||||
|
/* Now we have copied the data from INP and access only OUTP. */
|
||||||
|
|
||||||
|
DIRENT_SET_DP_INO (&outp->u, d_ino);
|
||||||
|
outp->u.d_off = d_off;
|
||||||
|
if ((sizeof (outp->u.d_ino) != sizeof (inp->k.d_ino)
|
||||||
|
&& outp->u.d_ino != d_ino)
|
||||||
|
|| (sizeof (outp->u.d_off) != sizeof (inp->k.d_off)
|
||||||
|
&& outp->u.d_off != d_off))
|
||||||
{
|
{
|
||||||
/* Overflow. If there was at least one entry
|
/* Overflow. If there was at least one entry
|
||||||
before this one, return them without error,
|
before this one, return them without error,
|
||||||
@ -169,23 +184,21 @@ __GETDENTS (int fd, char *buf, size_t nbytes)
|
|||||||
if (last_offset != -1)
|
if (last_offset != -1)
|
||||||
{
|
{
|
||||||
__lseek64 (fd, last_offset, SEEK_SET);
|
__lseek64 (fd, last_offset, SEEK_SET);
|
||||||
return (char *) dp - buf;
|
return outp->b - buf;
|
||||||
}
|
}
|
||||||
__set_errno (EOVERFLOW);
|
__set_errno (EOVERFLOW);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_offset = d_off;
|
last_offset = d_off;
|
||||||
dp->d_reclen = new_reclen;
|
outp->u.d_reclen = new_reclen;
|
||||||
dp->d_type = d_type;
|
outp->u.d_type = d_type;
|
||||||
memmove (dp->d_name, kdp->d_name,
|
|
||||||
old_reclen - offsetof (struct kernel_dirent64, d_name));
|
|
||||||
|
|
||||||
dp = (DIRENT_TYPE *) ((char *) dp + new_reclen);
|
inp = (void *) inp + old_reclen;
|
||||||
kdp = (struct kernel_dirent64 *) ((char *) kdp + old_reclen);
|
outp = (void *) outp + new_reclen;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (char *) dp - buf;
|
return outp->b - buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifndef __ASSUME_GETDENTS64_SYSCALL
|
# ifndef __ASSUME_GETDENTS64_SYSCALL
|
||||||
@ -205,7 +218,6 @@ __GETDENTS (int fd, char *buf, size_t nbytes)
|
|||||||
* size_diff),
|
* size_diff),
|
||||||
nbytes - size_diff);
|
nbytes - size_diff);
|
||||||
|
|
||||||
dp = (DIRENT_TYPE *) buf;
|
|
||||||
skdp = kdp = __alloca (red_nbytes);
|
skdp = kdp = __alloca (red_nbytes);
|
||||||
|
|
||||||
retval = INLINE_SYSCALL (getdents, 3, fd,
|
retval = INLINE_SYSCALL (getdents, 3, fd,
|
||||||
@ -214,6 +226,7 @@ __GETDENTS (int fd, char *buf, size_t nbytes)
|
|||||||
if (retval == -1)
|
if (retval == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
DIRENT_TYPE *dp = (DIRENT_TYPE *) buf;
|
||||||
while ((char *) kdp < (char *) skdp + retval)
|
while ((char *) kdp < (char *) skdp + retval)
|
||||||
{
|
{
|
||||||
const size_t alignment = __alignof__ (DIRENT_TYPE);
|
const size_t alignment = __alignof__ (DIRENT_TYPE);
|
||||||
@ -250,7 +263,7 @@ __GETDENTS (int fd, char *buf, size_t nbytes)
|
|||||||
dp = (DIRENT_TYPE *) ((char *) dp + new_reclen);
|
dp = (DIRENT_TYPE *) ((char *) dp + new_reclen);
|
||||||
kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen);
|
kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return (char *) dp - buf;
|
return (char *) dp - buf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user