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>
