[PATCH v2 1/5] mips: Do not malloc on getdents64 fallback
Adhemerval Zanella
adhemerval.zanella@linaro.org
Mon Nov 2 22:10:32 GMT 2020
On 02/11/2020 16:51, Joseph Myers wrote:
> On Tue, 8 Oct 2019, Adhemerval Zanella wrote:
>
>> + memcpy (((char *)(dp) + offsetof (struct dirent64, d_ino)),
>> + DP_MEMBER (kdp, struct kernel_dirent, d_ino),
>> + sizeof ((struct dirent64){0}.d_ino));
>> + memcpy (((char *)(dp) + offsetof (struct dirent64, d_off)),
>> + DP_MEMBER (kdp, struct kernel_dirent, d_ino),
>> + sizeof ((struct dirent64){0}.d_ino));
>
> (This is slightly different from the version of the code that ended up
> getting committed.)
>
> GCC mainline now gives a rather cryptic error about this code:
>
> ../sysdeps/unix/sysv/linux/mips/mips64/getdents64.c: In function '__getdents64':
> ../sysdeps/unix/sysv/linux/mips/mips64/getdents64.c:121:7: error: 'memcpy' forming offset [4, 7] is out of the bounds [0, 4] [-Werror=array-bounds]
> 121 | memcpy (((char *) dp + offsetof (struct dirent64, d_ino)),
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 122 | KDP_MEMBER (kdp, d_ino), sizeof ((struct dirent64){0}.d_ino));
> | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../sysdeps/unix/sysv/linux/mips/mips64/getdents64.c:123:7: error: 'memcpy' forming offset [4, 7] is out of the bounds [0, 4] [-Werror=array-bounds]
> 123 | memcpy (((char *) dp + offsetof (struct dirent64, d_off)),
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 124 | KDP_MEMBER (kdp, d_off), sizeof ((struct dirent64){0}.d_off));
> | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> I think what this error is pointing out is that the field in
> kernel_dirent, for non-n64, is 32-bit, while this is using memcpy to copy
> 64 bits from it into the glibc dirent64, which obviously doesn't work.
>
I was trying to be too clever to avoid a temporary variable to handle
mips64n32. I think the below should handle the issue raised by GCC11,
I will just check some on mips64 machine from gcc farm before send the
fix.
---
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c b/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c
index d18a5297dc..2ea1369ef4 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c
+++ b/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c
@@ -90,16 +90,29 @@ __getdents64 (int fd, void *buf, size_t nbytes)
while ((char *) kdp < (char *) skdp + r)
{
- /* This macro is used to avoid aliasing violation. */
-#define KDP_MEMBER(src, member) \
- (__typeof__((struct kernel_dirent){0}.member) *) \
- memcpy (&((__typeof__((struct kernel_dirent){0}.member)){0}), \
- ((char *)(src) + offsetof (struct kernel_dirent, member)),\
- sizeof ((struct kernel_dirent){0}.member))
+#define KDP_MEMBER(src, member) \
+ ({ \
+ __typeof ((struct kernel_dirent){0}.member) kdp_tmp; \
+ memcpy (&kdp_tmp, \
+ ((char *)(src) + offsetof (struct kernel_dirent, member)), \
+ sizeof (kdp_tmp)); \
+ kdp_tmp; \
+ })
+
+ /* Copy the MEMBER from SRC kernel_dirent to DST dirent64. It handles
+ the different size of d_off/d_ino for mips64-n32 by using temporary
+ variables. */
+#define COPY_MEMBER(src, dst, member) \
+ ({ \
+ __typeof ((struct dirent64){0}.member) dp_tmp \
+ = KDP_MEMBER (src, member); \
+ memcpy ((char *) dp + offsetof (struct dirent64, d_off), \
+ &dp_tmp, sizeof (dp_tmp)); \
+ })
/* This is a conservative approximation, since some of size_diff might
fit into the existing padding for alignment. */
- unsigned short int k_reclen = *KDP_MEMBER (kdp, d_reclen);
+ unsigned short int k_reclen = KDP_MEMBER (kdp, d_reclen);
unsigned short int new_reclen = ALIGN_UP (k_reclen + size_diff,
_Alignof (struct dirent64));
if (nb + new_reclen > nbytes)
@@ -118,11 +131,10 @@ __getdents64 (int fd, void *buf, size_t nbytes)
}
nb += new_reclen;
- memcpy (((char *) dp + offsetof (struct dirent64, d_ino)),
- KDP_MEMBER (kdp, d_ino), sizeof ((struct dirent64){0}.d_ino));
- memcpy (((char *) dp + offsetof (struct dirent64, d_off)),
- KDP_MEMBER (kdp, d_off), sizeof ((struct dirent64){0}.d_off));
- last_offset = *KDP_MEMBER (kdp, d_off);
+ COPY_MEMBER (dp, kdp, d_off);
+ COPY_MEMBER (dp, kdp, d_ino);
+
+ last_offset = KDP_MEMBER (kdp, d_off);
memcpy (((char *) dp + offsetof (struct dirent64, d_reclen)),
&new_reclen, sizeof (new_reclen));
dp->d_type = *((char *) kdp + k_reclen - 1);
More information about the Libc-alpha
mailing list