]> Savannah Git Hosting - gnulib.git/commitdiff
jit/cache tests: Fix crash with clang's UBSAN + ASAN.
authorBruno Haible <bruno@clisp.org>
Fri, 20 Sep 2024 15:17:36 +0000 (17:17 +0200)
committerBruno Haible <bruno@clisp.org>
Tue, 1 Oct 2024 21:00:57 +0000 (23:00 +0200)
* tests/jit/test-cache.c (clang_ubsan_workaround): New variable.
(CODE, SET_CODE): Use it.
(main): Initialize it.
* m4/libdl.m4: New file.
* modules/jit/cache-tests (Files): Add it.
(configure.ac): Invoke gl_LIBDL.
(Makefile.am): Link test-cache with $(LIBDL).

ChangeLog
m4/libdl.m4 [new file with mode: 0644]
modules/jit/cache-tests
tests/jit/test-cache.c

index 56c270222d115c33ed8f6012161a2151d2d151c4..9426e7dd9f37a74048dc672255d5421f621d7abf 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2024-09-20  Bruno Haible  <bruno@clisp.org>
+
+       jit/cache tests: Fix crash with clang's UBSAN + ASAN.
+       * tests/jit/test-cache.c (clang_ubsan_workaround): New variable.
+       (CODE, SET_CODE): Use it.
+       (main): Initialize it.
+       * m4/libdl.m4: New file.
+       * modules/jit/cache-tests (Files): Add it.
+       (configure.ac): Invoke gl_LIBDL.
+       (Makefile.am): Link test-cache with $(LIBDL).
+
 2024-09-20  KO Myung-Hun  <komh78@gmail.com>
 
        wait-process: Use waitpid() of LIBCx on OS/2 kLIBC if available.
diff --git a/m4/libdl.m4 b/m4/libdl.m4
new file mode 100644 (file)
index 0000000..f613960
--- /dev/null
@@ -0,0 +1,45 @@
+# libdl.m4
+# serial 1
+dnl Copyright (C) 2024 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+dnl Set LIBDL to '-ldl' if it is needed to use the functions declared
+dnl in <dlfcn.h> (dlopen, dlsym, etc.), or to empty otherwise.
+AC_DEFUN([gl_LIBDL],
+[
+  dnl dlopen, dlsym are
+  dnl - in libc on glibc >= 2.34, musl libc, macOS, FreeBSD, NetBSD, OpenBSD,
+  dnl   AIX, IRIX,  Solaris, Cygwin, Haiku,
+  dnl - in a separate libdl on glibc < 2.34, Android.
+  AC_CACHE_CHECK([for library needed for dlopen and dlsym],
+    [gl_cv_lib_dl],
+    [AC_LINK_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <dlfcn.h>
+          ]],
+          [[return ! dlsym (RTLD_DEFAULT, "main");]])],
+       [gl_cv_lib_dl=none],
+       [gl_cv_lib_dl=maybe])
+     if test $gl_cv_lib_dl = maybe; then
+       saved_LIBS="$LIBS"
+       LIBS="$LIBS -ldl"
+       AC_LINK_IFELSE(
+         [AC_LANG_PROGRAM(
+            [[#include <dlfcn.h>
+            ]],
+            [[return ! dlsym (RTLD_DEFAULT, "main");]])],
+         [gl_cv_lib_dl='-ldl'],
+         [gl_cv_lib_dl=none])
+       LIBS="$saved_LIBS"
+     fi
+    ])
+  case "$gl_cv_lib_dl" in
+    none) LIBDL='' ;;
+    *)    LIBDL="$gl_cv_lib_dl" ;;
+  esac
+  AC_SUBST([LIBDL])
+])
index aa6f37ce87dccd3e8a98170de968d06f98aaf215..d8163d62067417f2d13b9493621864b80f68be67 100644 (file)
@@ -3,6 +3,7 @@ tests/jit/test-cache.c
 tests/macros.h
 m4/mmap-anon.m4
 m4/warnings.m4
+m4/libdl.m4
 
 Status:
 unportable-test
@@ -17,6 +18,7 @@ xalloc
 configure.ac:
 AC_CHECK_HEADERS_ONCE([sys/mman.h])
 gl_FUNC_MMAP_ANON
+gl_LIBDL
 dnl Disable the OpenBSD "retguard" stack protector for this test.
 gl_COMPILER_OPTION_IF([-fno-ret-protector],
   [DISABLE_OPENBSD_RETGUARD='-fno-ret-protector'],
@@ -29,4 +31,4 @@ TESTS += test-cache
 check_PROGRAMS += test-cache
 test_cache_SOURCES = jit/test-cache.c
 test_cache_CFLAGS = $(AM_CFLAGS) $(DISABLE_OPENBSD_RETGUARD)
-test_cache_LDADD = $(LDADD) $(LIBINTL)
+test_cache_LDADD = $(LDADD) $(LIBINTL) @LIBDL@
index d19c720eb93c993d80aec8edf2a0858e412324d8..eeb6e2988db294a8595fd44f609c973cfa591c71 100644 (file)
 #include "xalloc.h"
 #include "macros.h"
 
-/*  On most platforms, function pointers are just a pointer to the
-    code, i.e. to the first instruction to be executed.  This,
-    however, is not universally true, see:
-    https://git.savannah.gnu.org/gitweb/?p=libffcall.git;a=blob;f=porting-tools/abis/function-pointer.txt.  */
+/* With clang ≥ 17, when the undefined-behaviour sanitizer is in use, 8 bytes of
+   meta-information precede each function: a magic number 0xC105CAFE and a word
+   that encodes the function's signature.  See
+   <https://reviews.llvm.org/D148665>
+   <https://github.com/llvm/llvm-project/issues/65253>
+   <https://www.reddit.com/r/C_Programming/comments/1dj9gg8/>  */
+#if defined __clang__ && __clang_major__ >= 17 && defined __ELF__
+# include <dlfcn.h>
+#endif
+static int clang_ubsan_workaround = 0;
+
+/* On most platforms, function pointers are just a pointer to the
+   code, i.e. to the first instruction to be executed.  This,
+   however, is not universally true, see:
+   https://git.savannah.gnu.org/gitweb/?p=libffcall.git;a=blob;f=porting-tools/abis/function-pointer.txt.  */
 
 #if ((defined __powerpc__ || defined __powerpc64__) && defined _AIX) || (defined __powerpc64__ && !defined __powerpc64_elfv2__ && defined __linux__)
 struct func
@@ -103,9 +114,9 @@ struct func
      ((void) ((funcptr) = \
               (void *) (((uintptr_t) (funcptr) & ~(intptr_t)1) | (is))))
 # else
-#  define CODE(funcptr) (funcptr)
+#  define CODE(funcptr) ((char *) (funcptr) - clang_ubsan_workaround)
 #  define SET_CODE(funcptr,code_addr) \
-     ((void) ((funcptr) = (void *) (code_addr)))
+     ((void) ((funcptr) = (void *) ((char *) (code_addr) + clang_ubsan_workaround)))
 #  define IS(funcptr) ((void) (funcptr), 0)
 #  define SET_IS(funcptr,is) ((void) (funcptr), (void) (is))
 # endif
@@ -234,6 +245,12 @@ unsigned int const return2_code[] = { 0x81c3e008, 0x90102002 };
 int
 main ()
 {
+#if defined __clang__ && __clang_major__ >= 17 && defined __ELF__
+  if (dlsym (RTLD_DEFAULT, "__ubsan_handle_function_type_mismatch") != NULL)
+    /* This program is built with clang ≥ 17 and its UBSAN.  */
+    clang_ubsan_workaround = 8;
+#endif
+
   void const *code_of_return1;
   void const *code_of_return2;
   size_t size_of_return1;