git » libfiu » commit 724df7e

preload/posix: Don't build 64-bit variants if the functions are aliases

author Alberto Bertogli
2024-06-09 08:37:06 UTC
committer Alberto Bertogli
2024-06-09 16:05:55 UTC
parent 1f659e4165072905776c1005238428a975cbffcd

preload/posix: Don't build 64-bit variants if the functions are aliases

Some platforms alias 64-bit functions at the asm level, in which case we
need to skip generating the 64-bit variants. Otherwise, we get errors
at linking time, such as:

  /tmp/cct4HXD3.s:1810: Error: symbol `pread64' is already defined

This is caused by us defining both the base (e.g. pread) and 64-bit
variant (e.g. pread64) on the same file; which normally works, unless
the 64-bit variant is declared as an asm aliases in the system headers.

See https://bugs.debian.org/1066938 for more details.

.gitignore +1 -0
preload/posix/Makefile +10 -2
preload/posix/build-check-redefine-64.c +30 -0
preload/posix/build-env.h.in +3 -0
preload/posix/codegen.h +1 -0
preload/posix/generate +9 -1
preload/posix/modules/posix.custom.c +3 -1

diff --git a/.gitignore b/.gitignore
index b80b6b7..9e445d9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ preload/posix/*.so
 preload/posix/build-flags
 preload/posix/build-libcsoname
 preload/posix/build-needlibdl
+preload/posix/build-check-redefine-64
 preload/posix/build-env.h
 preload/posix/function_list
 preload/posix/modules/*.o
diff --git a/preload/posix/Makefile b/preload/posix/Makefile
index 5c6162c..ecc5c55 100644
--- a/preload/posix/Makefile
+++ b/preload/posix/Makefile
@@ -92,12 +92,19 @@ build-libcsoname:
 	@test "`cat $@`" != "" || \
 		(echo "Error finding soname, please report"; rm $@; exit 1)
 
-build-env.h: build-env.h.in build-libcsoname
+# Some platforms alias 64-bit functions at the asm level, in which case we
+# need to skip generating the 64-bit variants.
+# This helper detects that situation.
+build-check-redefine-64:
+	@$(CC) -c build-check-redefine-64.c -o /dev/null 2>/dev/null \
+		&& echo 1 > $@ || echo 0 > $@
+
+build-env.h: build-env.h.in build-libcsoname build-check-redefine-64
 	@echo "  GEN $@"
 	$(Q) sed "s+@@LIBC_SONAME@@+`cat build-libcsoname`+g" build-env.h.in \
+		| sed "s+@@CAN_DEFINE_64BIT_FUNCTIONS@@+`cat build-check-redefine-64`+g" \
 		> build-env.h
 
-
 fiu_posix_preload.so: build-flags build-env.h build-needlibdl \
 		$(OBJS) ../../libfiu/hash.c
 	$(NICE_CC) $(ALL_CFLAGS) -shared -fPIC $(OBJS) ../../libfiu/hash.c \
@@ -124,6 +131,7 @@ uninstall:
 clean:
 	rm -f $(OBJS) $(GEN_OBJS:.o=.c) $(GEN_FL)
 	rm -f build-flags build-env.h build-libcsoname build-needlibdl
+	rm -f build-check-redefine-64
 	rm -f function_list fiu_posix_preload.so
 	rm -f *.bb *.bbg *.da *.gcov *.gcda *.gcno gmon.out
 	rm -f modules/*.bb modules/*.bbg modules/*.da
diff --git a/preload/posix/build-check-redefine-64.c b/preload/posix/build-check-redefine-64.c
new file mode 100644
index 0000000..b5b0e4f
--- /dev/null
+++ b/preload/posix/build-check-redefine-64.c
@@ -0,0 +1,30 @@
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <errno.h>
+
+// Some platforms the functions that have 64-bit (e.g. pread64, pwrite64) have
+// an assembler alias declared for the base variant in the header; while other
+// platforms don't do that and have the two functions declared separately.
+//
+// On the platforms that use assembler aliases, we can't redefine the 64-bit
+// variants.
+//
+// See https://bugs.debian.org/1066938 for more details.
+//
+// To detect this, we define both functions here. If there is an assembler
+// alias declared in the header, then compiling this will result in an error
+// like "Error: symbol `pread64' is already defined".
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset) {
+	return 0;
+}
+
+ssize_t pread64(int fd, void *buf, size_t count, off_t offset) {
+	return 0;
+}
diff --git a/preload/posix/build-env.h.in b/preload/posix/build-env.h.in
index 63c06f6..8e6f5cf 100644
--- a/preload/posix/build-env.h.in
+++ b/preload/posix/build-env.h.in
@@ -9,4 +9,7 @@
 /* libc's soname, used for dlopen()ing the C library */
 #define LIBC_SONAME "@@LIBC_SONAME@@"
 
+/* Whether 64-bit functions can be defined alongside the base ones */
+#define LIBFIU_CAN_DEFINE_64BIT_FUNCTIONS @@CAN_DEFINE_64BIT_FUNCTIONS@@
+
 #endif
diff --git a/preload/posix/codegen.h b/preload/posix/codegen.h
index 5ca27a8..2272f47 100644
--- a/preload/posix/codegen.h
+++ b/preload/posix/codegen.h
@@ -2,6 +2,7 @@
 #ifndef _FIU_CODEGEN
 #define _FIU_CODEGEN
 
+#include "build-env.h"
 #include <fiu.h>		/* fiu_* */
 #include <stdlib.h>		/* NULL, random() */
 
diff --git a/preload/posix/generate b/preload/posix/generate
index 5e1999a..c13dbe6 100755
--- a/preload/posix/generate
+++ b/preload/posix/generate
@@ -185,7 +185,15 @@ class Function:
 		f.ret_type = f.ret_type.replace("off_t", "off64_t")
 
 		# This is glibc-specific, so surround it with #ifdefs.
-		return [Verbatim("#ifdef __GLIBC__"), f, Verbatim("#endif")]
+        # Also only apply it if we can define the 64-bit functions on the same
+        # file (detected at build-time).
+		return [
+                Verbatim("#ifdef __GLIBC__"),
+                Verbatim("#if LIBFIU_CAN_DEFINE_64BIT_FUNCTIONS"),
+                f,
+                Verbatim("#endif  // LIBFIU_CAN_DEFINE_64BIT_FUNCTIONS"),
+                Verbatim("#endif  // __GLIBC__"),
+                ]
 
 	def get_all_variants(self):
 		"""Returns all variants of the given function provided via
diff --git a/preload/posix/modules/posix.custom.c b/preload/posix/modules/posix.custom.c
index 4f8b5fc..ceb99a5 100644
--- a/preload/posix/modules/posix.custom.c
+++ b/preload/posix/modules/posix.custom.c
@@ -103,6 +103,7 @@ mkwrap_bottom(open, (pathname, flags, mode))
 /* The 64-bit variant for glibc.
  * The code is identical to open(), just using open64() where appropriate. */
 #ifdef __GLIBC__
+#if LIBFIU_CAN_DEFINE_64BIT_FUNCTIONS
 
 mkwrap_init(int, open64, (const char *pathname, int flags, ...),
 		(const char *, int, ...))
@@ -183,7 +184,8 @@ mkwrap_body_called(open, (pathname, flags, mode), -1)
 mkwrap_body_errno("posix/io/oc/open", -1)
 mkwrap_bottom(open64, (pathname, flags, mode))
 
-#endif
+#endif  // LIBFIU_CAN_DEFINE_64BIT_FUNCTIONS
+#endif  // __GLIBC__
 
 /*
  * To simulate ferror() properly, we need to keep track of which FILE * have