* 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 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.
--- /dev/null
+# 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])
+])
tests/macros.h
m4/mmap-anon.m4
m4/warnings.m4
+m4/libdl.m4
Status:
unportable-test
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'],
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@
#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
((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
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;