[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