fix regression in alignment of dirent structs produced by readdir
authorRich Felker <dalias@aerifal.cx>
Wed, 18 Jul 2018 17:25:48 +0000 (13:25 -0400)
committerRich Felker <dalias@aerifal.cx>
Wed, 18 Jul 2018 17:34:34 +0000 (13:34 -0400)
commit 32482f61da7650ff10741bd5aedd66bbc3ea165b reduced the number of
int members before the dirent buf from 4 to 3, thereby misaligning it
mod sizeof(off_t), producing invalid accesses on any arch where
alignof(off_t)==sizeof(off_t).

rather than re-adding wasted padding, reorder the struct to meet the
requirement and add a comment and static assertion to prevent this
from getting broken again.

src/dirent/__dirent.h
src/dirent/readdir.c

index 101b036838baab73f4b6d0cb67773b288f978209..828a5f178917a97426d4fa35784494d894d25ccc 100644 (file)
@@ -1,9 +1,11 @@
 struct __dirstream
 {
-       int fd;
        off_t tell;
+       int fd;
        int buf_pos;
        int buf_end;
        volatile int lock[1];
+       /* Any changes to this struct must preserve the property:
+        * offsetof(struct __dirent, buf) % sizeof(off_t) == 0 */
        char buf[2048];
 };
index 2cf0632c207ef2547d6dfe8b67ed23783cf151d4..dc5f3edbd8c43aea9034a33c7d94aebc449cddef 100644 (file)
@@ -1,9 +1,13 @@
 #include <dirent.h>
 #include <errno.h>
+#include <stddef.h>
 #include "__dirent.h"
 #include "syscall.h"
 #include "libc.h"
 
+typedef char dirstream_buf_alignment_check[1-2*(int)(
+       offsetof(struct __dirstream, buf) % sizeof(off_t))];
+
 int __getdents(int, struct dirent *, size_t);
 
 struct dirent *readdir(DIR *dir)