summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanny Milosavljevic <dannym@scratchpost.org>2020-10-04 00:03:00 +0200
committerDanny Milosavljevic <dannym@scratchpost.org>2020-10-04 00:05:40 +0200
commit6d513b776a449fdb5c7c50b33060a5476edf61cb (patch)
treee7a9ce671a5c2437ae82b1f9b49e363ad6afd0f2
parent0585a0d0d1fe6e334d36e2d851b42b47d6769546 (diff)
gnu: glibc: Catch all cases of a glibc user not requesting 64-bit offsets and
then using readdir regardless. * gnu/packages/base.scm (glibc)[arguments]#<:phases>[patch-dirent]: Catch all cases of a glibc user not requesting 64-bit offsets and then using readdir regardless.
-rw-r--r--gnu/packages/base.scm64
1 files changed, 64 insertions, 0 deletions
diff --git a/gnu/packages/base.scm b/gnu/packages/base.scm
index 41976c5ab0..a5c41b5947 100644
--- a/gnu/packages/base.scm
+++ b/gnu/packages/base.scm
@@ -782,6 +782,70 @@ the store.")
#:tests? #f ; XXX
#:phases (modify-phases %standard-phases
+ (add-after 'unpack 'patch-dirent
+ (lambda* (#:key outputs #:allow-other-keys)
+ ;; Linux kernel file offsets are always 64 bits.
+ ;; But userspace can be built to use 32 bit offsets.
+ ;;
+ ;; "struct dirent", returned by readdir, uses d_off to store
+ ;; such an "offset" that it got from the Linux kernel.
+ ;; In the case of ext4 that "offset" is actually a 64 bit
+ ;; hash value.
+ ;;
+ ;; Therefore, there are cases where such an offset that it got
+ ;; from the Linux kernel does not fit in the "struct dirent"
+ ;; field "d_off".
+ ;;
+ ;; If the guest system's glibc is 32 bit AND uses 32 bit
+ ;; file offsets it is going to be very confused.
+ ;; It does check whether d_off fits into the structure
+ ;; it gives back to the user--and it doesn't fit. Hence readdir
+ ;; fails, with errno == EOVERFLOW (which is undocumented and thus
+ ;; an API error).
+ ;; This manifests itself in simple directory reads not working
+ ;; anymore in parts of cmake, for example.
+ ;;
+ ;; This manifested in Guix when building stuff for
+ ;; ARMHF on a x86_64 build host using QEMU transparent emulation.
+ ;;
+ ;; There is a very simple and complete way to avoid this problem:
+ ;; Just always use 64 bit offsets in user space programs (also
+ ;; on 32 bit machines). The Linux kernel does that already
+ ;; anyway.
+ ;;
+ ;; Note: We might want to avoid using 64 bit when bootstrapping
+ ;; using mescc (since mescc doesn't directly support 64 bit
+ ;; values)--but then bootstrapping has to be done on a
+ ;; file system other than ext4, or on ext4 with the feature
+ ;; "dir_index" disabled.
+ ;;
+ ;; The change below does not affect 64 bit users.
+ ;;
+ ;; See <https://issues.guix.gnu.org/43513>.
+ (let ((port (open-file "dirent/dirent.h" "a")))
+ (display "
+#ifndef _LIBC
+#if __SIZEOF_LONG__ < 8
+#ifndef __USE_FILE_OFFSET64
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 32
+#warning \"Using -D_FILE_OFFSET_BITS=32 and using readdir is a bad idea, see <https://bugzilla.kernel.org/show_bug.cgi?id=205957>\"
+#else
+#undef readdir
+#define readdir @READDIR_WITHOUT_FILE_OFFSET64_IS_A_REALLY_BAD_IDEA@
+#endif
+#endif
+#endif
+#endif
+" port)
+ (close-port port))
+ ;; This file includes <dirent.h> and thus checks sanity already.
+ ;; TODO: Check dirent/scandir-tail.c, dirent/scandir64-tail.c.
+ (substitute* "posix/glob.c"
+ (("(#[ ]*define[ ][ ]*readdir)") "
+#undef readdir
+#define readdir"))
+ #t))
+
(add-before
'configure 'pre-configure
(lambda* (#:key inputs native-inputs outputs