From c1bdab716d9671393aa3ce1e2e5cb1bc4066689d Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Fri, 20 Sep 2024 17:17:36 +0200 Subject: [PATCH] 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). --- ChangeLog | 11 ++++++++++ m4/libdl.m4 | 45 +++++++++++++++++++++++++++++++++++++++++ modules/jit/cache-tests | 4 +++- tests/jit/test-cache.c | 29 ++++++++++++++++++++------ 4 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 m4/libdl.m4 diff --git a/ChangeLog b/ChangeLog index 56c270222d..9426e7dd9f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2024-09-20 Bruno Haible + + 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 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 index 0000000000..f613960b61 --- /dev/null +++ b/m4/libdl.m4 @@ -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 (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 + ]], + [[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 + ]], + [[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]) +]) diff --git a/modules/jit/cache-tests b/modules/jit/cache-tests index aa6f37ce87..d8163d6206 100644 --- a/modules/jit/cache-tests +++ b/modules/jit/cache-tests @@ -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@ diff --git a/tests/jit/test-cache.c b/tests/jit/test-cache.c index d19c720eb9..eeb6e2988d 100644 --- a/tests/jit/test-cache.c +++ b/tests/jit/test-cache.c @@ -39,10 +39,21 @@ #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 + + + */ +#if defined __clang__ && __clang_major__ >= 17 && defined __ELF__ +# include +#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; -- 2.39.5