diff mbox series

[01/11] ubsan: Add initial support for -fsanitize=undefined

Message ID 20250507142110.3452012-2-adhemerval.zanella@linaro.org
State New
Headers show
Series Add initial support for --enable-ubsan | expand

Commit Message

Adhemerval Zanella May 7, 2025, 2:17 p.m. UTC
It is enabled through a new configure flag, --enable-ubsan, and
should be used for debugging and/or testing.  Not all ubsan handlers
are implemented, only those generated/required by glibc libraries,
programs, and tests.  Some extra handlers might be needed in future
C++ tests, and __ubsan_handle_dynamic_type_cache_miss also needs a
proper implementation.

The ubsan handlers are exported from ld.so since they are used on
all libraries and tests.  This might interfere with ubsan from
compiler runtime (when programs are built with libubsan in shared
mode), and this is completely untested and/or not supported at the
moment.

There is no support for the UBSAN_OPTIONS environment variable,
although some options are supported through glibc.ubsan tunables.
Currently, glibc.ubsan.halt_on_errors can be used to avoid
the process halt when any UB handler is issued.

Using -fsanitize=undefined enables some extra compiler checks that
are not easily enabled through the libc-diag.h macro.  For instance
on iconv/iconvconfig.c, gcc 14.2.1 shows:

In file included from ../include/bits/string_fortified.h:1,
                 from ../string/string.h:548,
                 from ../include/string.h:60,
                 from iconvconfig.c:32:
In function ‘strcpy’,
    inlined from ‘write_output’ at iconvconfig.c:1033:7,
    inlined from ‘main’ at iconvconfig.c:340:14:
../string/bits/string_fortified.h:81:10: error: ‘__builtin_memcpy’ offset [0, 7] is out of the bounds [0, 0] [-Werror=array-bounds=]
   81 |   return __builtin___strcpy_chk (__dest, __src, __glibc_objsize (__dest));
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../string/bits/string_fortified.h:81:10: error: ‘__builtin_memcpy’ offset [0, 7] is out of the bounds [0, 0] [-Werror=array-bounds=]
cc1: all warnings being treated as errors

Some extra code adjustments are required to fix such cases.

This preliminary support is still incomplete:

  * Not all targets are supported, nor have I checked the test suitei
    on all successful targets.  Also, I only checked with limited gcc
    versions (only gcc 14.2.1 and for some targets 15.0.0).

    Currently --enable-ubsan builds on Linux for aarch64, arm, hppa,
    i686, powerpc64, microblaze, mips64, loongarch64, sparc, s390x, and
    x86_64.

  * The instrumentation is disabled on rltd.c, although it is enabled
    on other loaders functions.

  * A lot of test cases show failures due to UB.

Also, gcc-14 triggers an ICE building math routines.  gcc-15
works correctly.
---
 INSTALL                                       |   9 +
 Makeconfig                                    |   6 +-
 config.h.in                                   |   3 +
 configure                                     |  30 ++
 configure.ac                                  |  18 +
 elf/Makefile                                  |  32 +-
 elf/Versions                                  |  19 +
 elf/dl-printf.c                               |   6 +
 elf/dl-tunables.list                          |   9 +
 elf/tst-_dl_addr_inside_object.c              |  12 +
 elf/ubsan_error.c                             |  57 +++
 elf/ubsan_handle_add_overflow.c               |  26 ++
 elf/ubsan_handle_builtin_unreachable.c        |  27 ++
 elf/ubsan_handle_divrem_overflow.c            |  40 +++
 elf/ubsan_handle_dynamic_type_cache_miss.c    |  28 ++
 elf/ubsan_handle_invalid_builtin.c            |  39 +++
 elf/ubsan_handle_load_invalid_value.c         |  33 ++
 elf/ubsan_handle_mul_overflow.c               |  26 ++
 elf/ubsan_handle_negate_overflow.c            |  34 ++
 elf/ubsan_handle_nonnull_arg.c                |  34 ++
 elf/ubsan_handle_nonnull_return_v1.c          |  34 ++
 elf/ubsan_handle_out_of_bounds.c              |  34 ++
 elf/ubsan_handle_overflow.c                   |  39 +++
 elf/ubsan_handle_pointer_overflow.c           |  62 ++++
 elf/ubsan_handle_shift_out_of_bounds.c        |  53 +++
 elf/ubsan_handle_sub_overflow.c               |  26 ++
 elf/ubsan_handle_type_mismatch_v1.c           |  75 ++++
 elf/ubsan_handle_vla_bound_not_positive.c     |  34 ++
 elf/ubsan_val_to_string.c                     | 189 ++++++++++
 elf/ubsan_vptr_type_cache.c                   |  21 ++
 iconv/iconvconfig.c                           |  13 +-
 include/libintl.h                             |   3 +
 include/sys/cdefs.h                           |   6 +
 include/ubsan.h                               | 327 ++++++++++++++++++
 locale/programs/locfile.h                     |   3 +-
 manual/install.texi                           |   8 +
 nss/test-netdb.c                              |   6 +
 posix/glob.c                                  |   5 +-
 resolv/res_send.c                             |  11 +-
 stdio-common/tst-printf-format-s.h            |   4 +
 stdio-common/tst-printf-format-vs.h           |   4 +
 stdlib/stdbit.h                               |   9 +-
 sysdeps/arm/Makefile                          |   5 +
 sysdeps/generic/ldconfig.h                    |   3 +-
 sysdeps/generic/ldsodefs.h                    |   3 +
 sysdeps/generic/symbol-hacks.h                |  36 ++
 .../powerpc64/multiarch/stpncpy-ppc64.c       |   3 +-
 47 files changed, 1473 insertions(+), 31 deletions(-)
 create mode 100644 elf/ubsan_error.c
 create mode 100644 elf/ubsan_handle_add_overflow.c
 create mode 100644 elf/ubsan_handle_builtin_unreachable.c
 create mode 100644 elf/ubsan_handle_divrem_overflow.c
 create mode 100644 elf/ubsan_handle_dynamic_type_cache_miss.c
 create mode 100644 elf/ubsan_handle_invalid_builtin.c
 create mode 100644 elf/ubsan_handle_load_invalid_value.c
 create mode 100644 elf/ubsan_handle_mul_overflow.c
 create mode 100644 elf/ubsan_handle_negate_overflow.c
 create mode 100644 elf/ubsan_handle_nonnull_arg.c
 create mode 100644 elf/ubsan_handle_nonnull_return_v1.c
 create mode 100644 elf/ubsan_handle_out_of_bounds.c
 create mode 100644 elf/ubsan_handle_overflow.c
 create mode 100644 elf/ubsan_handle_pointer_overflow.c
 create mode 100644 elf/ubsan_handle_shift_out_of_bounds.c
 create mode 100644 elf/ubsan_handle_sub_overflow.c
 create mode 100644 elf/ubsan_handle_type_mismatch_v1.c
 create mode 100644 elf/ubsan_handle_vla_bound_not_positive.c
 create mode 100644 elf/ubsan_val_to_string.c
 create mode 100644 elf/ubsan_vptr_type_cache.c
 create mode 100644 include/ubsan.h
diff mbox series

Patch

diff --git a/INSTALL b/INSTALL
index d3200f271f..50466cbfba 100644
--- a/INSTALL
+++ b/INSTALL
@@ -292,6 +292,15 @@  passed to 'configure'.  For example:
 
      Default is to disable fortification.
 
+'--enable-ubsan'
+     Build the GNU C library with, along with tests, with the
+     -fsanitize=undefined compiler option.  The compiler runtime is not
+     used, instead UBSAN functions called by the compiler instrumentation
+     is provided by glibc itself.
+
+     This is a debug/development option and the default is to disable
+     the instrumentation.
+
    To build the library and related programs, type 'make'.  This will
 produce a lot of output, some of which may look like errors from 'make'
 but aren't.  Look for error messages from 'make' containing '***'.
diff --git a/Makeconfig b/Makeconfig
index a2ea4f6a33..110ae79063 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -995,12 +995,14 @@  ifeq	"$(strip $(+cflags))" ""
 +cflags	:= $(default_cflags)
 endif	# $(+cflags) == ""
 
++ubsan-flags = $(cflags-enable-ubsan)
+
 # Force building with -fno-common because hidden_def, compat_symbol
 # and other constructs do not work for common symbols (and would
 # otherwise require specifying __attribute__ ((nocommon)) on a
 # case-by-case basis).
 +cflags += $(cflags-cpu) $(+gccwarn) $(+merge-constants) $(+math-flags) \
-	   $(+stack-protector) -fno-common
+	   $(+stack-protector) $(+ubsan-flags) -fno-common
 +gcc-nowarn := -w
 
 # We must filter out elf because the early bootstrap of the dynamic loader
@@ -1046,7 +1048,7 @@  libio-include = -I$(..)libio
 built-modules = iconvprogs iconvdata ldconfig libmemusage \
 		libpcprofile librpcsvc locale-programs \
 		memusagestat nonlib nscd extramodules libnldbl libsupport \
-		testsuite testsuite-internal
+		testsuite testsuite-internal libubsan
 
 in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \
 				    $(libof-$(<F)) \
diff --git a/config.h.in b/config.h.in
index d3575c9845..fd6013c52b 100644
--- a/config.h.in
+++ b/config.h.in
@@ -227,6 +227,9 @@ 
 /* An integer used to scale the timeout of test programs.  */
 #define TIMEOUTFACTOR 1
 
+/* Define if glibc should be build with -fsanitize=undefined.  */
+#undef ENABLE_UBSAN
+
 /*
  */
 
diff --git a/configure b/configure
index 7cda641fce..230adcf56c 100755
--- a/configure
+++ b/configure
@@ -701,6 +701,8 @@  INSTALL_DATA
 INSTALL_SCRIPT
 INSTALL_PROGRAM
 base_machine
+cflags_disable_ubsan
+cflags_enable_ubsan
 build_pt_chown
 build_nscd
 memory_tagging
@@ -820,6 +822,7 @@  enable_mathvec
 enable_cet
 enable_scv
 enable_fortify_source
+enable_ubsan
 with_cpu
 '
       ac_precious_vars='build_alias
@@ -1505,6 +1508,7 @@  Optional Features:
                           Use -D_FORTIFY_SOURCE=[1|2|3] to control code
                           hardening, defaults to highest possible value
                           supported by the build compiler.
+  --enable-ubsan          Build glibc with -fsanitize=undefined
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -4883,6 +4887,32 @@  case "$enable_fortify_source" in
 *) as_fn_error $? "Not a valid argument for --enable-fortify-source: \"$enable_fortify_source\"" "$LINENO" 5;;
 esac
 
+cflags_enable_ubsan=
+cflags_disable_ubsan=
+# Check whether --enable-ubsan was given.
+if test ${enable_ubsan+y}
+then :
+  enableval=$enable_ubsan; enable_ubsan=$enableval
+else case e in #(
+  e) enable_ubsan=no ;;
+esac
+fi
+
+config_vars="$config_vars
+enable-ubsan = $enable_ubsan"
+if test "$enable_ubsan" = yes; then
+  printf "%s\n" "#define ENABLE_UBSAN 1" >>confdefs.h
+
+  cflags_enable_ubsan="-fsanitize=undefined"
+  cflags_disable_ubsan="-fno-sanitize=undefined"
+fi
+
+
+config_vars="$config_vars
+cflags-enable-ubsan = $cflags_enable_ubsan"
+config_vars="$config_vars
+cflags-disable-ubsan = $cflags_disable_ubsan"
+
 # We keep the original values in `$config_*' and never modify them, so we
 # can write them unchanged into config.make.  Everything else uses
 # $machine, $vendor, and $os, and changes them whenever convenient.
diff --git a/configure.ac b/configure.ac
index 0b0d8875cc..95eacfaaf6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -440,6 +440,24 @@  case "$enable_fortify_source" in
 *) AC_MSG_ERROR([Not a valid argument for --enable-fortify-source: "$enable_fortify_source"]);;
 esac
 
+cflags_enable_ubsan=
+cflags_disable_ubsan=
+AC_ARG_ENABLE(ubsan,
+	      AS_HELP_STRING([--enable-ubsan],
+			     [Build glibc with -fsanitize=undefined]),
+	      [enable_ubsan=$enableval],
+	      [enable_ubsan=no])
+LIBC_CONFIG_VAR([enable-ubsan], [$enable_ubsan])
+if test "$enable_ubsan" = yes; then
+  AC_DEFINE(ENABLE_UBSAN)
+  cflags_enable_ubsan="-fsanitize=undefined"
+  cflags_disable_ubsan="-fno-sanitize=undefined"
+fi
+AC_SUBST(cflags_enable_ubsan)
+AC_SUBST(cflags_disable_ubsan)
+LIBC_CONFIG_VAR([cflags-enable-ubsan], [$cflags_enable_ubsan])
+LIBC_CONFIG_VAR([cflags-disable-ubsan], [$cflags_disable_ubsan])
+
 # We keep the original values in `$config_*' and never modify them, so we
 # can write them unchanged into config.make.  Everything else uses
 # $machine, $vendor, and $os, and changes them whenever convenient.
diff --git a/elf/Makefile b/elf/Makefile
index ed1b0223da..8d1bc9ea16 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -48,9 +48,35 @@  routines = \
   rtld_static_init \
   # routines
 
+ifeq (yes,$(enable-ubsan))
+ubsan-routines = \
+  ubsan_error \
+  ubsan_handle_add_overflow \
+  ubsan_handle_builtin_unreachable \
+  ubsan_handle_divrem_overflow \
+  ubsan_handle_dynamic_type_cache_miss \
+  ubsan_handle_invalid_builtin \
+  ubsan_handle_load_invalid_value \
+  ubsan_handle_mul_overflow \
+  ubsan_handle_negate_overflow \
+  ubsan_handle_nonnull_arg \
+  ubsan_handle_nonnull_return_v1 \
+  ubsan_handle_out_of_bounds \
+  ubsan_handle_overflow \
+  ubsan_handle_pointer_overflow \
+  ubsan_handle_shift_out_of_bounds \
+  ubsan_handle_sub_overflow \
+  ubsan_handle_type_mismatch_v1 \
+  ubsan_handle_vla_bound_not_positive \
+  ubsan_val_to_string \
+  ubsan_vptr_type_cache \
+  # ubsan-routines
+endif
+
 # The core dynamic linking functions are in libc for the static and
 # profiled libraries.
 dl-routines = \
+  $(ubsan-routines) \
   dl-call-libc-early-init \
   dl-call_fini \
   dl-catch \
@@ -102,6 +128,8 @@  ifeq (yes,$(have-loop-to-function))
 CFLAGS-dl-tunables.c += -fno-tree-loop-distribute-patterns
 endif
 
+CFLAGS-ubsan_handle_builtin_unreachable.c += -fno-builtin
+
 all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
 # But they are absent from the shared libc, because that code is in ld.so.
 elide-routines.os = \
@@ -160,7 +188,7 @@  CFLAGS-dl-minimal-malloc.op = $(no-stack-protector)
 # On targets without __builtin_memset, rtld.c uses a hand-coded loop
 # in _dl_start.  Make sure this isn't turned into a call to regular memset.
 ifeq (yes,$(have-loop-to-function))
-CFLAGS-rtld.c += -fno-tree-loop-distribute-patterns
+CFLAGS-rtld.c += -fno-tree-loop-distribute-patterns $(cflags-disable-ubsan)
 endif
 
 # Compile rtld itself without stack protection.
@@ -3434,7 +3462,7 @@  endif
 # ld.so.  The test is always run directly, not under the dynamic
 # linker.  It is necessary to minimize run-time dependencies, by
 # disabling stack protection and unwinding.
-CFLAGS-tst-nolink-libc.c += $(no-stack-protector) \
+CFLAGS-tst-nolink-libc.c += $(no-stack-protector) $(cflags-disable-ubsan) \
  -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables
 $(objpfx)tst-nolink-libc-1: $(objpfx)tst-nolink-libc.o $(objpfx)ld.so
 	$(LINK.o) -nostdlib -nostartfiles -o $@ $< \
diff --git a/elf/Versions b/elf/Versions
index 1591031da9..ca95312021 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -79,5 +79,24 @@  ld {
     # Set value of a tunable.
     __tunable_is_initialized;
     __tunable_get_val;
+
+    # -fsanitize=undefined support
+    __ubsan_handle_add_overflow;
+    __ubsan_handle_builtin_unreachable;
+    __ubsan_handle_divrem_overflow;
+    __ubsan_handle_dynamic_type_cache_miss;
+    __ubsan_handle_invalid_builtin;
+    __ubsan_handle_load_invalid_value;
+    __ubsan_handle_mul_overflow;
+    __ubsan_handle_negate_overflow;
+    __ubsan_handle_nonnull_arg;
+    __ubsan_handle_nonnull_return_v1;
+    __ubsan_handle_out_of_bounds;
+    __ubsan_handle_pointer_overflow;
+    __ubsan_handle_shift_out_of_bounds;
+    __ubsan_handle_sub_overflow;
+    __ubsan_handle_type_mismatch_v1;
+    __ubsan_handle_vla_bound_not_positive;
+    __ubsan_vptr_type_cache;
   }
 }
diff --git a/elf/dl-printf.c b/elf/dl-printf.c
index ebfc7eee86..cbaeb4acf7 100644
--- a/elf/dl-printf.c
+++ b/elf/dl-printf.c
@@ -269,6 +269,12 @@  _dl_debug_printf_c (const char *fmt, ...)
 }
 
 
+void
+_dl_debug_vprintf_c (const char *fmt, va_list ap)
+{
+  _dl_debug_vdprintf (GLRO(dl_debug_fd), -1, fmt, ap);
+}
+
 /* Write the given file descriptor.  */
 void
 _dl_dprintf (int fd, const char *fmt, ...)
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index c03c9967f0..9644940229 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -177,4 +177,13 @@  glibc {
       default: 1048576
     }
   }
+
+  ubsan {
+    halt_on_errors {
+      type: INT_32
+      minval: 0
+      maxval: 1
+      default: 1
+    }
+  }
 }
diff --git a/elf/tst-_dl_addr_inside_object.c b/elf/tst-_dl_addr_inside_object.c
index 0ef70a28a9..dbb74885e7 100644
--- a/elf/tst-_dl_addr_inside_object.c
+++ b/elf/tst-_dl_addr_inside_object.c
@@ -24,6 +24,18 @@ 
 
 extern int _dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr);
 
+#ifdef ENABLE_UBSAN
+void __GI___ubsan_handle_pointer_overflow (void *d, void *v, void *r)
+{
+  return __ubsan_handle_pointer_overflow (d, v, r);
+}
+
+void __GI___ubsan_handle_type_mismatch_v1 (void *d, void *p)
+{
+  return __ubsan_handle_type_mismatch_v1 (d, p);
+}
+#endif
+
 static int
 do_test (void)
 {
diff --git a/elf/ubsan_error.c b/elf/ubsan_error.c
new file mode 100644
index 0000000000..6922a1d933
--- /dev/null
+++ b/elf/ubsan_error.c
@@ -0,0 +1,57 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <abort-instr.h>
+#include <ubsan.h>
+#include <dl-tunables.h>
+
+static void _Noreturn
+ubsan_abort (void)
+{
+  /* abort() pulls a lot of extra definition from libc (rwlock, signal
+     hanlding, pthread, etc.; so use a more simpler implementation for
+     now.  */
+  raise (SIGABRT);
+
+#ifdef ABORT_INSTRUCTION
+  ABORT_INSTRUCTION;
+#endif
+  _exit (127);
+}
+
+void
+__ubsan_error (const struct source_location *source,
+	       const char *fmt,
+	       ...)
+{
+  _dl_debug_printf_c ("UBSAN: Undefined behaviour in %s:%u:%u ",
+		      get_source_location_file_name (source),
+		      get_source_location_line (source),
+		      get_source_location_column (source));
+
+  va_list ap;
+  va_start (ap, fmt);
+  _dl_debug_vprintf_c (fmt, ap);
+  va_end (ap);
+
+  if (TUNABLE_GET (glibc, ubsan, halt_on_errors, int32_t, NULL))
+    ubsan_abort ();
+}
diff --git a/elf/ubsan_handle_add_overflow.c b/elf/ubsan_handle_add_overflow.c
new file mode 100644
index 0000000000..b2463268cf
--- /dev/null
+++ b/elf/ubsan_handle_add_overflow.c
@@ -0,0 +1,26 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "ubsan.h"
+
+void
+__ubsan_handle_add_overflow (void *_data, void *lhs, void *rhs)
+{
+  __ubsan_handle_overflow (_data, lhs, rhs, "+");
+}
+rtld_hidden_def (__ubsan_handle_add_overflow)
diff --git a/elf/ubsan_handle_builtin_unreachable.c b/elf/ubsan_handle_builtin_unreachable.c
new file mode 100644
index 0000000000..b2a7dde5c7
--- /dev/null
+++ b/elf/ubsan_handle_builtin_unreachable.c
@@ -0,0 +1,27 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "ubsan.h"
+
+void
+__ubsan_handle_builtin_unreachable (void *_data)
+{
+   struct unreachable_data *data = _data;
+   __ubsan_error (&data->location, "calling __builtin_unreachable()\n");
+}
+rtld_hidden_def (__ubsan_handle_builtin_unreachable)
diff --git a/elf/ubsan_handle_divrem_overflow.c b/elf/ubsan_handle_divrem_overflow.c
new file mode 100644
index 0000000000..bf5788c2fd
--- /dev/null
+++ b/elf/ubsan_handle_divrem_overflow.c
@@ -0,0 +1,40 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "ubsan.h"
+
+void
+__ubsan_handle_divrem_overflow (void *_data, void *lhs, void *rhs)
+{
+  struct overflow_data *data = _data;
+  char lhs_str[UBSAN_VAL_STR_LEN];
+  char rhs_str[UBSAN_VAL_STR_LEN];
+
+  __ubsan_val_to_string (lhs_str, data->type, lhs);
+  __ubsan_val_to_string (rhs_str, data->type, rhs);
+
+  if (ubsan_type_is_signed (data->type)
+      && ubsan_get_signed_val (data->type, rhs))
+    __ubsan_error (&data->location,
+		   "division overflow: division of %s by -1 cannot be "
+		   "represented in type %s\n",
+		   rhs_str, data->type->type_name);
+  else
+    __ubsan_error (&data->location, "division by zero");
+}
+rtld_hidden_def (__ubsan_handle_divrem_overflow)
diff --git a/elf/ubsan_handle_dynamic_type_cache_miss.c b/elf/ubsan_handle_dynamic_type_cache_miss.c
new file mode 100644
index 0000000000..b5be609a0d
--- /dev/null
+++ b/elf/ubsan_handle_dynamic_type_cache_miss.c
@@ -0,0 +1,28 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ubsan.h>
+
+
+void
+__ubsan_handle_dynamic_type_cache_miss (void *_data, void *pointer, void *hash)
+{
+  /* TODO: this failure requires additional check to check for real
+     issues.  Ignore for now.  */
+}
+rtld_hidden_def (__ubsan_handle_dynamic_type_cache_miss)
diff --git a/elf/ubsan_handle_invalid_builtin.c b/elf/ubsan_handle_invalid_builtin.c
new file mode 100644
index 0000000000..4518408ab1
--- /dev/null
+++ b/elf/ubsan_handle_invalid_builtin.c
@@ -0,0 +1,39 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ubsan.h>
+
+void
+__ubsan_handle_invalid_builtin (void *_data)
+{
+  struct invalid_builtin_data *data = _data;
+  switch (data->kind)
+    {
+    case ubsan_builtin_check_kind_assume_passed_false:
+      __ubsan_error (&data->location,
+		     "assumption is violated during execution\n");
+      break;
+    default:
+      __ubsan_error (&data->location,
+		     "passing zero to __builtin_%s()\n",
+		     data->kind == ubsan_builtin_check_kind_ctz_passed_zero
+		     ? "ctz" : "clz");
+      break;
+    }
+}
+rtld_hidden_def (__ubsan_handle_invalid_builtin)
diff --git a/elf/ubsan_handle_load_invalid_value.c b/elf/ubsan_handle_load_invalid_value.c
new file mode 100644
index 0000000000..b2b2e9b3cd
--- /dev/null
+++ b/elf/ubsan_handle_load_invalid_value.c
@@ -0,0 +1,33 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "ubsan.h"
+
+void
+__ubsan_handle_load_invalid_value (void *_data, void *val)
+{
+  struct invalid_value_data *data = _data;
+  char val_str[UBSAN_VAL_STR_LEN];
+
+  __ubsan_val_to_string (val_str, data->type, val);
+  __ubsan_error (&data->location,
+		 "load of value %s is not a valid value for type %s\n",
+		 val_str,
+		 data->type->type_name);
+}
+rtld_hidden_def (__ubsan_handle_load_invalid_value)
diff --git a/elf/ubsan_handle_mul_overflow.c b/elf/ubsan_handle_mul_overflow.c
new file mode 100644
index 0000000000..b0010b9329
--- /dev/null
+++ b/elf/ubsan_handle_mul_overflow.c
@@ -0,0 +1,26 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "ubsan.h"
+
+void
+__ubsan_handle_mul_overflow (void *_data, void *lhs, void *rhs)
+{
+  __ubsan_handle_overflow (_data, lhs, rhs, "*");
+}
+rtld_hidden_def (__ubsan_handle_mul_overflow)
diff --git a/elf/ubsan_handle_negate_overflow.c b/elf/ubsan_handle_negate_overflow.c
new file mode 100644
index 0000000000..bb0c12ea5e
--- /dev/null
+++ b/elf/ubsan_handle_negate_overflow.c
@@ -0,0 +1,34 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "ubsan.h"
+
+void
+__ubsan_handle_negate_overflow (void *_data, void *val)
+{
+  struct overflow_data *data = _data;
+  char val_str[UBSAN_VAL_STR_LEN];
+
+  __ubsan_val_to_string(val_str, data->type, val);
+
+  __ubsan_error (&data->location,
+		 "negation of %s cannot be represented in type %s\n",
+		 val_str,
+		 data->type->type_name);
+}
+rtld_hidden_def (__ubsan_handle_negate_overflow)
diff --git a/elf/ubsan_handle_nonnull_arg.c b/elf/ubsan_handle_nonnull_arg.c
new file mode 100644
index 0000000000..a5104fd49d
--- /dev/null
+++ b/elf/ubsan_handle_nonnull_arg.c
@@ -0,0 +1,34 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "ubsan.h"
+
+void
+__ubsan_handle_nonnull_arg (void *_data)
+{
+  struct nonnull_arg_data *data = _data;
+
+  __ubsan_error (&data->location,
+		 "null pointer passed as argument %u, nonnull attribute "
+		 "declared at %s:%u:%u\n",
+		 data->arg_index,
+		 get_source_location_file_name (&data->attr_location),
+		 get_source_location_line (&data->attr_location),
+		 get_source_location_column (&data->attr_location));
+}
+rtld_hidden_def (__ubsan_handle_nonnull_arg)
diff --git a/elf/ubsan_handle_nonnull_return_v1.c b/elf/ubsan_handle_nonnull_return_v1.c
new file mode 100644
index 0000000000..a6e0d73fef
--- /dev/null
+++ b/elf/ubsan_handle_nonnull_return_v1.c
@@ -0,0 +1,34 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ubsan.h>
+
+void
+__ubsan_handle_nonnull_return_v1 (void *_data, void *_location)
+{
+  struct nonnull_return_data *data = _data;
+  struct source_location *location = _location;
+
+  __ubsan_error (&data->location,
+		 "null pointer returned from function declared as "
+		 "returns_nonnull: source %s:%u:%u\n",
+		 get_source_location_file_name (location),
+		 get_source_location_line (location),
+		 get_source_location_column (location));
+}
+rtld_hidden_def (__ubsan_handle_nonnull_return_v1)
diff --git a/elf/ubsan_handle_out_of_bounds.c b/elf/ubsan_handle_out_of_bounds.c
new file mode 100644
index 0000000000..469682ddfd
--- /dev/null
+++ b/elf/ubsan_handle_out_of_bounds.c
@@ -0,0 +1,34 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "ubsan.h"
+
+void
+__ubsan_handle_out_of_bounds (void *_data, void *index)
+{
+  struct out_of_bounds_data *data = _data;
+  char index_str[UBSAN_VAL_STR_LEN];
+
+  __ubsan_val_to_string (index_str, data->index_type, index);
+
+  __ubsan_error (&data->location,
+		 "index %s is out of bounds for type %s\n",
+                 index_str,
+                 data->array_type->type_name);
+}
+rtld_hidden_def (__ubsan_handle_out_of_bounds)
diff --git a/elf/ubsan_handle_overflow.c b/elf/ubsan_handle_overflow.c
new file mode 100644
index 0000000000..865ad76e49
--- /dev/null
+++ b/elf/ubsan_handle_overflow.c
@@ -0,0 +1,39 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "ubsan.h"
+
+void
+__ubsan_handle_overflow (const struct overflow_data * data, void *lhs,
+			 void *rhs, const char *op)
+{
+  char lhs_str[UBSAN_VAL_STR_LEN];
+  char rhs_str[UBSAN_VAL_STR_LEN];
+
+  __ubsan_val_to_string (lhs_str, data->type, lhs);
+  __ubsan_val_to_string (rhs_str, data->type, rhs);
+
+  __ubsan_error (&data->location,
+		 "%s integer overflow: %s %s %s cannot be represened in "
+		 "type %s\n",
+		 ubsan_type_is_signed (data->type) ? "signed" : "unsigned",
+		 lhs_str,
+		 op,
+		 rhs_str,
+		 data->type->type_name);
+}
diff --git a/elf/ubsan_handle_pointer_overflow.c b/elf/ubsan_handle_pointer_overflow.c
new file mode 100644
index 0000000000..8d0c4db739
--- /dev/null
+++ b/elf/ubsan_handle_pointer_overflow.c
@@ -0,0 +1,62 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <ubsan.h>
+
+void
+__ubsan_handle_pointer_overflow (void *_data, void *val, void *result)
+{
+  struct pointer_overflow_data *data = _data;
+
+  if (val == NULL && result == NULL)
+    __ubsan_error (&data->location,
+		   "applying zero offset to a NULL pointer\n");
+  else if (val == NULL && result != NULL)
+    __ubsan_error (&data->location,
+		   "applying non-zero offset to a NULL pointer\n");
+  else if (val != NULL && result == NULL)
+    __ubsan_error (&data->location,
+		   "applying non-zero offset to non-NULL pointer 0x%0*lx "
+		   "produced NULL pointer\n",
+		   (int) sizeof (void *) * 2,
+		   (unsigned long int) val);
+  else if (((intptr_t)val >= 0) == ((intptr_t)result >= 0))
+    {
+      const char *operation = ((uintptr_t)val > (uintptr_t)result)
+	? "addition" : "subtraction";
+
+      __ubsan_error (&data->location,
+		     "%s of unsigned offset to 0x%0*lx overflowed "
+		     "to 0x%0*lx\n",
+		     operation,
+		     (int) sizeof (void *) * 2,
+		     (unsigned long int) val,
+		     (int) sizeof (void *) * 2,
+		     (unsigned long int) result);
+    }
+  else
+    __ubsan_error (&data->location,
+		   "pointer index expression with base 0x%0*lx overflowed "
+		   "to 0x%0*lx\n",
+		   (int) sizeof (void *) * 2,
+		   (unsigned long int) val,
+		   (int) sizeof (void *) * 2,
+		   (unsigned long int) result);
+}
+rtld_hidden_def (__ubsan_handle_pointer_overflow)
diff --git a/elf/ubsan_handle_shift_out_of_bounds.c b/elf/ubsan_handle_shift_out_of_bounds.c
new file mode 100644
index 0000000000..f8402778ba
--- /dev/null
+++ b/elf/ubsan_handle_shift_out_of_bounds.c
@@ -0,0 +1,53 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ubsan.h>
+
+void
+__ubsan_handle_shift_out_of_bounds (void *_data, void *lhs, void *rhs)
+{
+  struct shift_out_of_bounds_data *data = _data;
+  char lhs_str[UBSAN_VAL_STR_LEN];
+  char rhs_str[UBSAN_VAL_STR_LEN];
+
+  __ubsan_val_to_string (lhs_str, data->lhs_type, lhs);
+  __ubsan_val_to_string (rhs_str, data->rhs_type, rhs);
+
+  if (ubsan_val_is_negative (data->rhs_type, rhs))
+    __ubsan_error (&data->location,
+		   "shift expoenent %s is negative\n",
+		   rhs_str);
+  else if (ubsan_get_unsigned_val (data->rhs_type, rhs) >=
+	   ubsan_type_bit_width (data->lhs_type))
+    __ubsan_error (&data->location,
+		   "shift exponent %s is too large for %u-bit type %s\n",
+		   rhs_str,
+		   ubsan_type_bit_width (data->lhs_type),
+		   data->lhs_type->type_name);
+  else if (ubsan_val_is_negative (data->lhs_type, lhs))
+    __ubsan_error (&data->location,
+		   "left shift of negative valor %s\n",
+		   lhs_str);
+  else
+    __ubsan_error (&data->location,
+		   "left shift of %s by %s cannot be represented in type %s\n",
+		   lhs_str,
+		   rhs_str,
+		   data->lhs_type->type_name);
+}
+rtld_hidden_def (__ubsan_handle_shift_out_of_bounds)
diff --git a/elf/ubsan_handle_sub_overflow.c b/elf/ubsan_handle_sub_overflow.c
new file mode 100644
index 0000000000..8b576dae14
--- /dev/null
+++ b/elf/ubsan_handle_sub_overflow.c
@@ -0,0 +1,26 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ubsan.h>
+
+void
+__ubsan_handle_sub_overflow (void *_data, void *lhs, void *rhs)
+{
+  __ubsan_handle_overflow (_data, lhs, rhs, "-");
+}
+rtld_hidden_def (__ubsan_handle_sub_overflow)
diff --git a/elf/ubsan_handle_type_mismatch_v1.c b/elf/ubsan_handle_type_mismatch_v1.c
new file mode 100644
index 0000000000..de459b99f4
--- /dev/null
+++ b/elf/ubsan_handle_type_mismatch_v1.c
@@ -0,0 +1,75 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ubsan.h>
+
+static const char *
+type_check_to_string (unsigned char type_check_kind)
+{
+  switch (type_check_kind)
+    {
+    case ubsan_type_check_load: return "load of";
+    case ubsan_type_check_store: return "store to";
+    case ubsan_type_check_reference_binding: return "reference binding to";
+    case ubsan_type_check_member_access: return "member access within";
+    case ubsan_type_check_member_call: return "member call on";
+    case ubsan_type_check_constructor_call: return "constructor call on";
+    case ubsan_type_check_downcast_pointer:
+    case ubsan_type_check_downcast_reference: return "downcast of";
+    case ubsan_type_check_upcast: return "upcast of";
+    case ubsan_type_check_upcast_to_virtual_base: return "cast to virtual base of";
+    case ubsan_type_check_nonnull_assign: return "_Nonnull binding to";
+    case ubsan_type_check_dynamic_operation: return "dynamic operation on";
+    default: return "unknown";
+    }
+}
+
+static inline bool
+is_misaligned_pointer (const struct type_mismatch_data_v1 *data, void *ptr)
+{
+  uintptr_t alignment = 1UL << data->log_alignment;
+  return (uintptr_t) ptr & (alignment - 1);
+}
+
+void
+__ubsan_handle_type_mismatch_v1 (void *_data, void *ptr)
+{
+  struct type_mismatch_data_v1 *data = _data;
+
+  if (data->type_check_kind == ubsan_type_check_nonnull_assign)
+    __ubsan_error (&data->location,
+		   "%s null pointer of type %s\n",
+		   type_check_to_string (data->type_check_kind),
+		   data->type->type_name);
+  else if (is_misaligned_pointer (data, ptr))
+    __ubsan_error (&data->location,
+		   "%s misaligned address 0x%0*lx for type %s\n",
+		   type_check_to_string (data->type_check_kind),
+		   (int) sizeof (void *) * 2,
+		   (unsigned long int) ptr,
+		   data->type->type_name);
+  else
+    __ubsan_error (&data->location,
+		   "%s address 0x%0*lx with insufficient space for an "
+		   "object of type %s\n",
+		   type_check_to_string (data->type_check_kind),
+		   (int) sizeof (void *) * 2,
+		   (unsigned long int) ptr,
+		   data->type->type_name);
+}
+rtld_hidden_def (__ubsan_handle_type_mismatch_v1)
diff --git a/elf/ubsan_handle_vla_bound_not_positive.c b/elf/ubsan_handle_vla_bound_not_positive.c
new file mode 100644
index 0000000000..e2b3f5232d
--- /dev/null
+++ b/elf/ubsan_handle_vla_bound_not_positive.c
@@ -0,0 +1,34 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ubsan.h>
+
+void
+__ubsan_handle_vla_bound_not_positive (void *_data, void *bound)
+{
+  struct vla_bound_not_positive_data *data = _data;
+  char bound_str[UBSAN_VAL_STR_LEN];
+
+  __ubsan_val_to_string (bound_str, data->type, bound);
+
+  __ubsan_error (&data->location,
+		 "variable length array bound evaluates to "
+		 "non-positive value %s\n",
+		 bound_str);
+}
+rtld_hidden_def (__ubsan_handle_vla_bound_not_positive)
diff --git a/elf/ubsan_val_to_string.c b/elf/ubsan_val_to_string.c
new file mode 100644
index 0000000000..f354eed49d
--- /dev/null
+++ b/elf/ubsan_val_to_string.c
@@ -0,0 +1,189 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <intprops.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ubsan.h"
+
+static const char lower_digits[] = "0123456789";
+
+enum { BASE = 10 };
+
+static char *
+utoa (unsigned long long int value, char *buf, size_t len)
+{
+  if (len == 0)
+    return buf;
+
+  char *ptr = buf;
+  do
+    {
+      if (len-- == 0)
+	break;
+      *ptr++ = lower_digits[value % BASE];
+      value /= BASE;
+    }
+  while (value != 0);
+  char *r = ptr;
+  *ptr-- = '\0';
+
+  while (buf < ptr)
+    {
+      char t = *ptr;
+      *ptr-- = *buf;
+      *buf++ = t;
+    }
+
+  return r;
+}
+
+static char *
+itoa (long long int value, char *buf, size_t len)
+{
+  if (len == 0)
+    return buf;
+
+  bool isneg = value < 0;
+  char *ptr = buf;
+  do
+    {
+      if (len-- == 0)
+	break;
+      *ptr++ = lower_digits[abs (value % BASE)];
+      value /= BASE;
+    }
+  while (value != 0);
+  if (isneg)
+    *ptr++ = '-';
+  char *r = ptr;
+  *ptr-- = '\0';
+
+  while (buf < ptr)
+    {
+      char t = *ptr;
+      *ptr-- = *buf;
+      *buf++ = t;
+    }
+
+  return r;
+}
+
+static long long int
+ubsan_val_to_ll (int width, void *value, long long int def)
+{
+  switch (width)
+    {
+    case 8:
+      return (int8_t) (intptr_t) value;
+    case 16:
+      return (int16_t) (intptr_t) value;
+    case 32:
+      if (sizeof (value) >= sizeof (int32_t))
+	return (int32_t) (intptr_t) value;
+      else
+	return *(int32_t *) value;
+    case 64:
+      if (sizeof (value) >= sizeof (int64_t))
+	return (int64_t) (intptr_t) value;
+      else
+	return *(int64_t *) value;
+    default:
+      return def;
+    }
+}
+
+static unsigned long long int
+ubsan_val_to_ull (int width, void *value, unsigned long long int def)
+{
+  switch (width)
+    {
+    case 8:
+      return (uint8_t) (uintptr_t) value;
+    case 16:
+      return (uint16_t) (uintptr_t) value;
+    case 32:
+      if (sizeof (value) >= sizeof (uint32_t))
+	return (uint32_t) (uintptr_t) value;
+      else
+	return *(uint32_t *) value;
+    case 64:
+      if (sizeof (value) >= sizeof (uint64_t))
+	return (uint64_t) (uintptr_t) value;
+      else
+	return *(uint64_t *) value;
+    default:
+      return def;
+    }
+}
+
+static inline char *
+add_string (char *str, const char *s, size_t *len)
+{
+  char *endp = __stpncpy (str, s, *len);
+  *len -= endp - str;
+  return endp;
+}
+
+static inline char *
+add_uint (char *str, unsigned long long int value, size_t *len)
+{
+  char *endp = utoa (value, str, *len);
+  *len -= endp - str;
+  return endp;
+}
+
+void
+__ubsan_val_to_string (char str[static UBSAN_VAL_STR_LEN],
+		       struct type_descriptor *type, void *value)
+{
+  int width = ubsan_type_bit_width (type);
+  switch (type->type_kind)
+    {
+    case ubsan_type_kind_int:
+      if (ubsan_type_is_signed (type))
+	{
+	  long long int v = ubsan_val_to_ll (width, value, 0);
+	  itoa (v, str, UBSAN_VAL_STR_LEN);
+	}
+      else
+	{
+	  unsigned long long int v = ubsan_val_to_ull (width, value, 0);
+	  utoa (v, str, UBSAN_VAL_STR_LEN);
+	}
+      break;
+    case ubsan_type_kind_float:
+      {
+	char *endp = __stpcpy (str, "float size ");
+	utoa (width, endp, UBSAN_VAL_STR_LEN);
+      }
+      break;
+    default:
+      {
+	size_t size = UBSAN_VAL_STR_LEN;
+	char *endp = add_string (str, "kind ", &size);
+	endp = add_uint (endp, type->type_kind, &size);
+	endp = add_string (endp, " (width ", &size);
+	endp = add_uint (endp, width, &size);
+	add_string (endp, " )", &size);
+      }
+      break;
+    }
+}
diff --git a/elf/ubsan_vptr_type_cache.c b/elf/ubsan_vptr_type_cache.c
new file mode 100644
index 0000000000..77572b2487
--- /dev/null
+++ b/elf/ubsan_vptr_type_cache.c
@@ -0,0 +1,21 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ubsan.h>
+
+unsigned int __ubsan_vptr_type_cache[UBSAN_VPTR_TYPE_CACHE_SIZE];
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
index aa6f381266..8975aa086e 100644
--- a/iconv/iconvconfig.c
+++ b/iconv/iconvconfig.c
@@ -1019,11 +1019,14 @@  write_output (void)
   /* Open the output file.  */
   if (output_file == NULL)
     {
-      assert (GCONV_MODULES_CACHE[0] == '/');
-      strcpy (stpcpy (mempcpy (tmpfname, prefix, prefix_len),
-		      GCONV_MODULES_CACHE),
-	      ".XXXXXX");
-      strcpy (mempcpy (finalname, prefix, prefix_len), GCONV_MODULES_CACHE);
+      snprintf (tmpfname, sizeof tmpfname, "%.*s%s.XXXXXX",
+		(int) prefix_len,
+		prefix,
+		GCONV_MODULES_CACHE);
+      snprintf (finalname, sizeof finalname, "%.*s%s",
+		(int) prefix_len,
+		prefix,
+		GCONV_MODULES_CACHE);
     }
   else
     strcpy (mempcpy (tmpfname, output_file, output_file_len), ".XXXXXX");
diff --git a/include/libintl.h b/include/libintl.h
index 3d63b7abbd..57039f1fc1 100644
--- a/include/libintl.h
+++ b/include/libintl.h
@@ -65,5 +65,8 @@  libc_hidden_proto (_libc_intl_domainname)
 # undef N_
 # define N_(msgid)	msgid
 
+# undef gettext
+# define gettext(msgid) (dgettext (NULL, msgid) ?: (char *)msgid)
+
 # endif /* !_ISOMAC */
 #endif
diff --git a/include/sys/cdefs.h b/include/sys/cdefs.h
index a676f75f62..8ec2079fa4 100644
--- a/include/sys/cdefs.h
+++ b/include/sys/cdefs.h
@@ -63,4 +63,10 @@  rtld_hidden_proto (__chk_fail)
 # define __attribute_optimization_barrier__ __attribute__ ((noinline, noclone))
 #endif
 
+#ifdef ENABLE_UBSAN
+# define __attribute_disable_ubsan__ __attribute__((no_sanitize("undefined")))
+#else
+# define __attribute_disable_ubsan__
+#endif
+
 #endif
diff --git a/include/ubsan.h b/include/ubsan.h
new file mode 100644
index 0000000000..56d8721507
--- /dev/null
+++ b/include/ubsan.h
@@ -0,0 +1,327 @@ 
+/* Undefined Behavior Sanitizer support.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef __UBSAN_H__
+#define __UBSAN_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <endian.h>
+
+#ifdef __SIZEOF_INT128__
+typedef __int128 ubsan_s_max;
+typedef unsigned __int128 ubsan_u_max;
+#else
+typedef int64_t ubsan_u_max;
+typedef uint64_t ubsan_s_max;
+#endif
+
+#define REPORTED_BIT 31
+#if (__WORDSIZE == 64 && BYTE_ORDER == BIG_ENDIAN)
+# define COLUMN_MASK  (~(1U << REPORTED_BIT))
+# define LINE_MASK    (~0U)
+#else
+# define COLUMN_MASK  (~0U)
+# define LINE_MASK    (~(1U << REPORTED_BIT))
+#endif
+
+struct source_location
+{
+  const char *file_name;
+  unsigned int line;
+  unsigned int column;
+};
+
+static inline const char *
+get_source_location_file_name (const struct source_location *location)
+{
+  return location->file_name ? location->file_name : "unknown";
+}
+
+static inline unsigned int
+get_source_location_line (const struct source_location *location)
+{
+  return location->line & LINE_MASK;
+}
+
+static inline unsigned int
+get_source_location_column (const struct source_location *location)
+{
+  return location->column & COLUMN_MASK;
+}
+
+struct nonnull_arg_data
+{
+  struct source_location location;
+  struct source_location attr_location;
+  int arg_index;
+};
+
+struct type_descriptor
+{
+  uint16_t type_kind;
+  uint16_t type_info;
+  char type_name[];
+};
+
+static inline bool
+ubsan_type_is_signed (const struct type_descriptor *type)
+{
+  return type->type_kind & 1;
+}
+
+static inline unsigned int
+ubsan_type_bit_width (const struct type_descriptor *type)
+{
+  return 1 << (type->type_info >> 1);
+}
+
+static inline bool
+ubsan_is_inline_int (const struct type_descriptor *type)
+{
+  unsigned int inline_bits = sizeof (unsigned long) * 8;
+  unsigned int bits = ubsan_type_bit_width (type);
+
+  return bits <= inline_bits;
+}
+
+static inline ubsan_s_max
+ubsan_get_signed_val (const struct type_descriptor *type, void *val)
+{
+  if (ubsan_is_inline_int (type))
+    {
+      unsigned int extra_bits = sizeof (ubsan_s_max) * 8
+	- ubsan_type_bit_width (type);
+      unsigned long ul_val = (unsigned long) val;
+      return ((ubsan_s_max) ul_val) << extra_bits >> extra_bits;
+    }
+
+  if (ubsan_type_bit_width (type) == 64)
+    return *(int64_t*) val;
+
+  return *(ubsan_s_max *) val;
+}
+
+static inline ubsan_u_max
+ubsan_get_unsigned_val (const struct type_descriptor *type, void *val)
+{
+  if (ubsan_is_inline_int (type))
+    return (unsigned long) val;
+
+  if (ubsan_type_bit_width (type) == 64)
+    return *(uint64_t*) val;
+
+  return *(ubsan_u_max *)val;
+}
+
+static inline bool
+ubsan_val_is_negative (const struct type_descriptor *type, void *val)
+{
+  return ubsan_type_is_signed (type) && ubsan_get_signed_val (type, val) < 0;
+}
+
+struct invalid_value_data
+{
+  struct source_location location;
+  struct type_descriptor *type;
+};
+
+/* The type_mismatch_data_v1::type_check_kind */
+enum
+{
+  ubsan_type_check_load,
+  ubsan_type_check_store,
+  ubsan_type_check_reference_binding,
+  ubsan_type_check_member_access,
+  ubsan_type_check_member_call,
+  ubsan_type_check_constructor_call,
+  ubsan_type_check_downcast_pointer,
+  ubsan_type_check_downcast_reference,
+  ubsan_type_check_upcast,
+  ubsan_type_check_upcast_to_virtual_base,
+  ubsan_type_check_nonnull_assign,
+  ubsan_type_check_dynamic_operation
+};
+
+struct type_mismatch_data_v1
+{
+  struct source_location location;
+  struct type_descriptor *type;
+  unsigned char log_alignment;
+  unsigned char type_check_kind;
+};
+
+struct pointer_overflow_data
+{
+  struct source_location location;
+};
+
+struct overflow_data
+{
+  struct source_location location;
+  struct type_descriptor *type;
+};
+
+struct out_of_bounds_data
+{
+  struct source_location location;
+  struct type_descriptor *array_type;
+  struct type_descriptor *index_type;
+};
+
+struct shift_out_of_bounds_data
+{
+  struct source_location location;
+  struct type_descriptor *lhs_type;
+  struct type_descriptor *rhs_type;
+};
+
+struct vla_bound_not_positive_data
+{
+  struct source_location location;
+  struct type_descriptor *type;
+};
+
+struct unreachable_data
+{
+  struct source_location location;
+};
+
+struct invalid_builtin_data
+{
+  struct source_location location;
+  unsigned char kind;
+};
+
+struct nonnull_return_data
+{
+  struct source_location location;
+};
+
+struct dynamic_type_cache_miss_data
+{
+  struct source_location location;
+  struct type_descriptor *type;
+  void *info;
+  unsigned char kind;
+};
+
+enum
+{
+  ubsan_type_kind_int = 0,
+  ubsan_type_kind_float = 1,
+  ubsan_type_unknown = 0xffff
+};
+
+enum
+{
+  ubsan_builtin_check_kind_ctz_passed_zero,
+  ubsan_builtin_check_kind_clz_passed_zero,
+  ubsan_builtin_check_kind_assume_passed_false,
+};
+
+#define UBSAN_VAL_STR_LEN     32
+
+void
+__ubsan_val_to_string (char str[static UBSAN_VAL_STR_LEN],
+		       struct type_descriptor *type, void *value)
+  attribute_hidden;
+
+#define UBSAN_VPTR_TYPE_CACHE_SIZE 128
+
+extern unsigned int __ubsan_vptr_type_cache[UBSAN_VPTR_TYPE_CACHE_SIZE];
+
+#if IS_IN(rtld)
+# define ubsan_hidden attribute_hidden
+#else
+# define ubsan_hidden
+#endif
+
+void __ubsan_error (const struct source_location *source,
+		    const char *fmt, ...)
+  __attribute__ ((__format__ (__printf__, 2, 3)))
+  attribute_hidden;
+
+void __ubsan_handle_overflow (const struct overflow_data *, void *,
+			      void *, const char *op)
+  attribute_hidden;
+
+void __ubsan_handle_load_invalid_value (void *data, void *value)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_load_invalid_value)
+
+void __ubsan_handle_type_mismatch_v1 (void *data, void *ptr)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_type_mismatch_v1)
+
+void __ubsan_handle_pointer_overflow (void *data, void *val, void *result)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_pointer_overflow)
+
+void __ubsan_handle_add_overflow (void *data, void *lhs, void *rhs)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_add_overflow)
+
+void __ubsan_handle_sub_overflow (void *data, void *lhs, void *rhs)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_sub_overflow)
+
+void __ubsan_handle_mul_overflow (void *data, void *lhs, void *rhs)
+  attribute_hidden;
+rtld_hidden_proto (__ubsan_handle_mul_overflow)
+
+void __ubsan_handle_out_of_bounds (void *data, void *index)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_out_of_bounds)
+
+void __ubsan_handle_negate_overflow (void *data, void *val)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_negate_overflow)
+
+void __ubsan_handle_shift_out_of_bounds (void *_data, void *lhs, void *rhs)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_shift_out_of_bounds)
+
+void __ubsan_handle_divrem_overflow (void *_data, void *lhs, void *rhs)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_divrem_overflow)
+
+void __ubsan_handle_vla_bound_not_positive (void *data, void *bound)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_vla_bound_not_positive)
+
+void __ubsan_handle_builtin_unreachable (void *data)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_builtin_unreachable)
+
+void __ubsan_handle_invalid_builtin (void *data)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_invalid_builtin)
+
+void __ubsan_handle_nonnull_arg (void *data)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_nonnull_arg);
+
+void __ubsan_handle_nonnull_return_v1 (void *data, void *location)
+  ubsan_hidden;
+rtld_hidden_proto (__ubsan_handle_nonnull_return_v1)
+
+void __ubsan_handle_dynamic_type_cache_miss (void *, void *, void *);
+rtld_hidden_proto (__ubsan_handle_dynamic_type_cache_miss)
+
+#endif /* __UBSAN_H__ */
diff --git a/locale/programs/locfile.h b/locale/programs/locfile.h
index 9103fade14..e0000bc392 100644
--- a/locale/programs/locfile.h
+++ b/locale/programs/locfile.h
@@ -124,7 +124,8 @@  extern void end_locale_structure (struct locale_file *file);
 extern void start_locale_prelude (struct locale_file *file);
 extern void end_locale_prelude (struct locale_file *file);
 extern void write_locale_data (const char *output_path, int catidx,
-			       const char *category, struct locale_file *file);
+			       const char *category, struct locale_file *file)
+     __attribute__ ((nonnull (1, 3, 4)));
 
 
 /* Entrypoints for the parsers of the individual categories.  */
diff --git a/manual/install.texi b/manual/install.texi
index 7fcdda9146..1e4242dff4 100644
--- a/manual/install.texi
+++ b/manual/install.texi
@@ -320,6 +320,14 @@  If not provided, @option{LEVEL} defaults to highest possible value supported by
 the build compiler.
 
 Default is to disable fortification.
+
+@item --enable-ubsan
+Build @theglibc{}, along with tests, with the @code{-fsanitize=undefined}
+compiler option.  The compiler runtime is not used, instead UBSAN functions
+called by the compiler instrumentation is provided by glibc itself.
+
+This is a debug/development option and the default is to disable
+the instrumentation.
 @end table
 
 To build the library and related programs, type @code{make}.  This will
diff --git a/nss/test-netdb.c b/nss/test-netdb.c
index 3fb9ba0a42..3911c3c42a 100644
--- a/nss/test-netdb.c
+++ b/nss/test-netdb.c
@@ -41,6 +41,9 @@ 
 
 #include <support/support.h>
 
+#define assume(R) ((R) ? (void) 0 : __builtin_unreachable ())
+#define assume_nonnull(x) assume ((x) != NULL)
+
 /*
   The following define is necessary for glibc 2.0.6
 */
@@ -180,6 +183,9 @@  test_hosts (void)
       namelen += 2;		/* tiny increments to test a lot */
       name = xrealloc (name, namelen);
     }
+
+  assume_nonnull (name);
+
   if (gethostname (name, namelen) == 0)
     {
       printf ("Hostname: %s\n", name);
diff --git a/posix/glob.c b/posix/glob.c
index a7c7dd1ebe..60ca0147ac 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -1397,9 +1397,10 @@  glob_in_dir (const char *pattern, const char *directory, int flags,
                         if (s.length < need
                             && !scratch_buffer_set_array_size (&s, need, 1))
                           goto memory_error;
-                        char *p = mempcpy (s.data, directory, dirlen);
+                        char *pdata = s.data;
+                        char *p = mempcpy (pdata, directory, dirlen);
                         *p = '/';
-                        p += p[-1] != '/';
+                        p += pdata[p - pdata - 1] != '/';
                         memcpy (p, d.name, namelen + 1);
                         if (! is_dir (s.data, flags, pglob))
                           continue;
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 802675995d..37444fc925 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -801,7 +801,7 @@  reopen (res_state statp, int *terrno, int ns)
 {
 	if (EXT(statp).nssocks[ns] == -1) {
 		struct sockaddr *nsap = __res_get_nsaddr (statp, ns);
-		socklen_t slen;
+		socklen_t slen = 0;
 
 		/* only try IPv6 if IPv6 NS and if not failed before */
 		if (nsap->sa_family == AF_INET6 && !statp->ipv6_unavail) {
@@ -845,16 +845,7 @@  reopen (res_state statp, int *terrno, int ns)
 		 * error message is received.  We can thus detect
 		 * the absence of a nameserver without timing out.
 		 */
-		/* With GCC 5.3 when compiling with -Os the compiler
-		   emits a warning that slen may be used uninitialized,
-		   but that is never true.  Both slen and
-		   EXT(statp).nssocks[ns] are initialized together or
-		   the function return -1 before control flow reaches
-		   the call to connect with slen.  */
-		DIAG_PUSH_NEEDS_COMMENT;
-		DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
 		if (__connect (EXT (statp).nssocks[ns], nsap, slen) < 0) {
-		DIAG_POP_NEEDS_COMMENT;
 			__res_iclose(statp, false);
 			return (0);
 		}
diff --git a/stdio-common/tst-printf-format-s.h b/stdio-common/tst-printf-format-s.h
index 20369b8e86..92946cbcba 100644
--- a/stdio-common/tst-printf-format-s.h
+++ b/stdio-common/tst-printf-format-s.h
@@ -21,6 +21,9 @@ 
 
 #include <support/next_to_fault.h>
 
+#define assume(R) ((R) ? (void) 0 : __builtin_unreachable ())
+#define assume_nonnull(x) assume ((x) != NULL)
+
 #define SPRINTF_BUFFER_SIZE 65536
 
 static struct support_next_to_fault ntf;
@@ -42,6 +45,7 @@  printf_under_test_fini (void)
 ({									\
   __label__ out;							\
   char *str = ntf.buffer;						\
+  assume_nonnull (str);							\
   int result;								\
 									\
   result = sprintf (str, __VA_ARGS__);					\
diff --git a/stdio-common/tst-printf-format-vs.h b/stdio-common/tst-printf-format-vs.h
index f99747a924..15d5341f80 100644
--- a/stdio-common/tst-printf-format-vs.h
+++ b/stdio-common/tst-printf-format-vs.h
@@ -22,6 +22,9 @@ 
 
 #include <support/next_to_fault.h>
 
+#define assume(R) ((R) ? (void) 0 : __builtin_unreachable ())
+#define assume_nonnull(x) assume ((x) != NULL)
+
 #define SPRINTF_BUFFER_SIZE 65536
 
 static struct support_next_to_fault ntf;
@@ -43,6 +46,7 @@  static int
 printf_under_test (const char *restrict fmt, ...)
 {
   char *str = ntf.buffer;
+  assume_nonnull (str);
   va_list ap;
   int result;
 
diff --git a/stdlib/stdbit.h b/stdlib/stdbit.h
index 4afa4362d1..36b92901e5 100644
--- a/stdlib/stdbit.h
+++ b/stdlib/stdbit.h
@@ -44,13 +44,8 @@  __BEGIN_DECLS
 /* Use __pacify_uint16 (N) instead of (uint16_t) (N) when the cast is helpful
    only to pacify older GCC (e.g., GCC 10 -Wconversion) or non-GCC (e.g
    clang -Wimplicit-int-conversion).  */
-#if __GNUC_PREREQ (11, 0)
-# define __pacify_uint8(n)  (n)
-# define __pacify_uint16(n) (n)
-#else
-# define __pacify_uint8(n)  ((uint8_t) (n))
-# define __pacify_uint16(n) ((uint16_t) (n))
-#endif
+#define __pacify_uint8(n)  ((uint8_t) (n))
+#define __pacify_uint16(n) ((uint16_t) (n))
 
 /* Count leading zeros.  */
 extern unsigned int stdc_leading_zeros_uc (unsigned char __x)
diff --git a/sysdeps/arm/Makefile b/sysdeps/arm/Makefile
index 9c4fd6b236..c7e92da053 100644
--- a/sysdeps/arm/Makefile
+++ b/sysdeps/arm/Makefile
@@ -31,6 +31,11 @@  $(objpfx)tst-armtlsdescextnow: $(objpfx)tst-armtlsdescextnowmod.so
 $(objpfx)tst-armtlsdescextlazy: $(objpfx)tst-armtlsdescextlazymod.so
 endif
 endif
+
+ifeq ($(enable-ubsan),yes)
+# aeabi_unwind_cpp_pr1 is built as rtld module
+CFLAGS-aeabi_unwind_cpp_pr1.c += -DDISABLE_USAN_INTERNAL_REDIR
+endif
 endif
 
 ifeq ($(subdir),csu)
diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h
index 7bc8788647..78e43d7038 100644
--- a/sysdeps/generic/ldconfig.h
+++ b/sysdeps/generic/ldconfig.h
@@ -84,7 +84,8 @@  extern int search_aux_cache (struct stat *stat_buf, int *flags,
 extern void add_to_aux_cache (struct stat *stat_buf, int flags,
 			      unsigned int isa_level, const char *soname);
 
-extern void save_aux_cache (const char *aux_cache_name);
+extern void save_aux_cache (const char *aux_cache_name)
+  __attribute__((nonnull (1)));
 
 /* Declared in readlib.c.  */
 extern int process_file (const char *real_file_name, const char *file_name,
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index fc4a3de767..527381222f 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -27,6 +27,7 @@ 
 #include <stddef.h>
 #include <string.h>
 #include <stdint.h>
+#include <stdarg.h>
 
 #include <elf.h>
 #include <dlfcn.h>
@@ -773,6 +774,8 @@  extern void _dl_debug_printf (const char *fmt, ...)
 extern void _dl_debug_printf_c (const char *fmt, ...)
      __attribute__ ((__format__ (__printf__, 1, 2))) attribute_hidden;
 
+extern void _dl_debug_vprintf_c (const char *fmt, va_list ap)
+     __attribute__ ((__format__ (__printf__, 1, 0))) attribute_hidden;
 
 /* Write a message on the specified descriptor FD.  The parameters are
    interpreted as for a `printf' call.  */
diff --git a/sysdeps/generic/symbol-hacks.h b/sysdeps/generic/symbol-hacks.h
index 1115e4c0a7..10a3a5388d 100644
--- a/sysdeps/generic/symbol-hacks.h
+++ b/sysdeps/generic/symbol-hacks.h
@@ -18,3 +18,39 @@  asm (".hidden __stack_chk_fail_local\n"
      "__stack_chk_fail = __stack_chk_fail_local");
 # endif
 #endif
+
+#if !defined __ASSEMBLER__ && IS_IN(rtld) && defined ENABLE_UBSAN \
+  && !defined DISABLE_USAN_INTERNAL_REDIR
+/* These are autogenerated by the compiler, so no subject to either
+   hidden_attribute or hidden_proto alias definition.  */
+asm ("__ubsan_handle_negate_overflow = "
+     "__GI___ubsan_handle_negate_overflow");
+asm ("__ubsan_handle_shift_out_of_bounds = "
+     "__GI___ubsan_handle_shift_out_of_bounds");
+asm ("__ubsan_handle_divrem_overflow = "
+     "__GI___ubsan_handle_divrem_overflow");
+asm ("__ubsan_handle_vla_bound_not_positive = "
+     "__GI___ubsan_handle_vla_bound_not_positive");
+asm ("__ubsan_handle_pointer_overflow = "
+     "__GI___ubsan_handle_pointer_overflow");
+asm ("__ubsan_handle_load_invalid_value ="
+     "__GI___ubsan_handle_load_invalid_value");
+asm ("__ubsan_handle_out_of_bounds = "
+     "__GI___ubsan_handle_out_of_bounds");
+asm ("__ubsan_handle_sub_overflow = "
+     "__GI___ubsan_handle_sub_overflow");
+asm ("__ubsan_handle_add_overflow = "
+     "__GI___ubsan_handle_add_overflow");
+asm ("__ubsan_handle_mul_overflow = "
+     "__GI___ubsan_handle_mul_overflow");
+asm ("__ubsan_handle_type_mismatch_v1 = "
+     "__GI___ubsan_handle_type_mismatch_v1");
+asm ("__ubsan_handle_nonnull_return_v1 = "
+     "__GI___ubsan_handle_nonnull_return_v1");
+asm ("__ubsan_handle_nonnull_arg = "
+     "__GI___ubsan_handle_nonnull_arg");
+asm ("__ubsan_handle_invalid_builtin = "
+     "__GI___ubsan_handle_invalid_builtin");
+asm ("__ubsan_handle_builtin_unreachable = "
+     "__GI___ubsan_handle_builtin_unreachable");
+#endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/stpncpy-ppc64.c b/sysdeps/powerpc/powerpc64/multiarch/stpncpy-ppc64.c
index e0a8747884..6dec085cb7 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/stpncpy-ppc64.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/stpncpy-ppc64.c
@@ -20,7 +20,8 @@ 
 #ifdef SHARED
 #undef libc_hidden_def
 #define libc_hidden_def(name) \
-  __hidden_ver1 (__stpncpy_ppc, __GI___stpncpy, __stpncpy_ppc);
+  __hidden_ver1 (__stpncpy_ppc, __GI___stpncpy, __stpncpy_ppc); \
+  weak_alias (__stpncpy_ppc, __stpncpy)
 #endif
 
 #include <string/stpncpy.c>