]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
ubsan: Add initial support for -fsanitize=undefined
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Wed, 16 Apr 2025 12:32:19 +0000 (09:32 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Wed, 7 May 2025 13:41:28 +0000 (10:41 -0300)
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.

47 files changed:
INSTALL
Makeconfig
config.h.in
configure
configure.ac
elf/Makefile
elf/Versions
elf/dl-printf.c
elf/dl-tunables.list
elf/tst-_dl_addr_inside_object.c
elf/ubsan_error.c [new file with mode: 0644]
elf/ubsan_handle_add_overflow.c [new file with mode: 0644]
elf/ubsan_handle_builtin_unreachable.c [new file with mode: 0644]
elf/ubsan_handle_divrem_overflow.c [new file with mode: 0644]
elf/ubsan_handle_dynamic_type_cache_miss.c [new file with mode: 0644]
elf/ubsan_handle_invalid_builtin.c [new file with mode: 0644]
elf/ubsan_handle_load_invalid_value.c [new file with mode: 0644]
elf/ubsan_handle_mul_overflow.c [new file with mode: 0644]
elf/ubsan_handle_negate_overflow.c [new file with mode: 0644]
elf/ubsan_handle_nonnull_arg.c [new file with mode: 0644]
elf/ubsan_handle_nonnull_return_v1.c [new file with mode: 0644]
elf/ubsan_handle_out_of_bounds.c [new file with mode: 0644]
elf/ubsan_handle_overflow.c [new file with mode: 0644]
elf/ubsan_handle_pointer_overflow.c [new file with mode: 0644]
elf/ubsan_handle_shift_out_of_bounds.c [new file with mode: 0644]
elf/ubsan_handle_sub_overflow.c [new file with mode: 0644]
elf/ubsan_handle_type_mismatch_v1.c [new file with mode: 0644]
elf/ubsan_handle_vla_bound_not_positive.c [new file with mode: 0644]
elf/ubsan_val_to_string.c [new file with mode: 0644]
elf/ubsan_vptr_type_cache.c [new file with mode: 0644]
iconv/iconvconfig.c
include/libintl.h
include/sys/cdefs.h
include/ubsan.h [new file with mode: 0644]
locale/programs/locfile.h
manual/install.texi
nss/test-netdb.c
posix/glob.c
resolv/res_send.c
stdio-common/tst-printf-format-s.h
stdio-common/tst-printf-format-vs.h
stdlib/stdbit.h
sysdeps/arm/Makefile
sysdeps/generic/ldconfig.h
sysdeps/generic/ldsodefs.h
sysdeps/generic/symbol-hacks.h
sysdeps/powerpc/powerpc64/multiarch/stpncpy-ppc64.c

diff --git a/INSTALL b/INSTALL
index d3200f271f1b604b538709a77827436908e89830..50466cbfba2c43fb6ef327ebc90d9267a7fead00 100644 (file)
--- 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 '***'.
index a2ea4f6a332520bc766c806c0832343884fc4e3d..110ae79063e4dffffc4cce3c0afa4c96dc6ac634 100644 (file)
@@ -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)) \
index d3575c98458ad3e1c591a6dc47db2aac6809bc15..fd6013c52b538363f6f1da6e17e9ea93ab4098f4 100644 (file)
 /* 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
+
 /*
 \f */
 
index 7cda641fcebeb06b03d71ac2df8519237e501614..230adcf56ca2b57ea4949e16d25f15443e411925 100755 (executable)
--- 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.
index 0b0d8875ccd9b97685ac7cf008602b6b67ab1133..95eacfaaf60f1a9eb09c7aeba4bbf64ef6e7bd34 100644 (file)
@@ -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.
index ed1b0223da67fcbdecebb6018420bf7bf1428edd..8d1bc9ea16001a7656e0eed2947f34c5aaef3c10 100644 (file)
@@ -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 $@ $< \
index 1591031da990eb93e3d190978a0cd2edf064a6a6..ca9531202166c9e58e71c04337a221f6f51c6cdf 100644 (file)
@@ -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;
   }
 }
index ebfc7eee86afb071ca260bcecc5878526cc50669..cbaeb4acf7c3a5055c5e42a57ad690ef7795d950 100644 (file)
@@ -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, ...)
index c03c9967f09a41ac3f3c05fc3851a7f360872ed1..96449402295ef053746c80e0d23c6e5ce0aac34d 100644 (file)
@@ -177,4 +177,13 @@ glibc {
       default: 1048576
     }
   }
+
+  ubsan {
+    halt_on_errors {
+      type: INT_32
+      minval: 0
+      maxval: 1
+      default: 1
+    }
+  }
 }
index 0ef70a28a9e644b91229a94d40de8a92bf5787ef..dbb74885e7ddd37447f3d282dbe54ed802f267d4 100644 (file)
 
 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 (file)
index 0000000..6922a1d
--- /dev/null
@@ -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 (file)
index 0000000..b246326
--- /dev/null
@@ -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 (file)
index 0000000..b2a7dde
--- /dev/null
@@ -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 (file)
index 0000000..bf5788c
--- /dev/null
@@ -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 (file)
index 0000000..b5be609
--- /dev/null
@@ -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 (file)
index 0000000..4518408
--- /dev/null
@@ -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 (file)
index 0000000..b2b2e9b
--- /dev/null
@@ -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 (file)
index 0000000..b0010b9
--- /dev/null
@@ -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 (file)
index 0000000..bb0c12e
--- /dev/null
@@ -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 (file)
index 0000000..a5104fd
--- /dev/null
@@ -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 (file)
index 0000000..a6e0d73
--- /dev/null
@@ -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 (file)
index 0000000..469682d
--- /dev/null
@@ -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 (file)
index 0000000..865ad76
--- /dev/null
@@ -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 (file)
index 0000000..8d0c4db
--- /dev/null
@@ -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 (file)
index 0000000..f840277
--- /dev/null
@@ -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 (file)
index 0000000..8b576da
--- /dev/null
@@ -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 (file)
index 0000000..de459b9
--- /dev/null
@@ -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 (file)
index 0000000..e2b3f52
--- /dev/null
@@ -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 (file)
index 0000000..f354eed
--- /dev/null
@@ -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 (file)
index 0000000..77572b2
--- /dev/null
@@ -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];
index aa6f381266bfdb31209d4684d7001d2c007b1f80..8975aa086e86ee658f1e9f84dad68085f014dd60 100644 (file)
@@ -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");
index 3d63b7abbd34521cecdfa99d6b8fc2f0310cecdf..57039f1fc13a80872401f687161db61b5755f24b 100644 (file)
@@ -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
index a676f75f6259a303edf27ca076c62764c5cceda0..8ec2079fa4d11c1c9d7726f4c9465ea62a781e43 100644 (file)
@@ -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 (file)
index 0000000..56d8721
--- /dev/null
@@ -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__ */
index 9103fade14e160ab6fc026bd3b2c5c12e7746c86..e0000bc3922ef617a065152f8b96a575f5abacbd 100644 (file)
@@ -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.  */
index 7fcdda9146b2e152be03d575cdda6f323b6c3fee..1e4242dff4fe2b79dd22714e430207261aecf9a1 100644 (file)
@@ -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
index 3fb9ba0a4272fd95e06365f3e3735adc496197f0..3911c3c42aa83eb83069bc757cc16d11a6bcfb7b 100644 (file)
@@ -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);
index a7c7dd1ebe10fe92b22d7d7b35d63fb73da030fe..60ca0147ac9bf22bdcf98be74e11dd7a249dd120 100644 (file)
@@ -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;
index 802675995d8033da7c18b1c64d862053f9bde8d6..37444fc925c2431de525d805d60b039ff902de8f 100644 (file)
@@ -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);
                }
index 20369b8e86072adc6cb38da3c981386ef047a5bd..92946cbcbae345f806569eee7d032a0b525d4fdb 100644 (file)
@@ -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__);                                 \
index f99747a92481697794adf575610b9730bc24df30..15d5341f8088bb59cc71430d99785e1c660dba1b 100644 (file)
@@ -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;
 
index 4afa4362d11821f1f207bf23350a3dacf066bdc1..36b92901e5b8a113506e239a97c85fe630a83f5f 100644 (file)
@@ -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)
index 9c4fd6b236967d91f8300a9b61aa84d58083c694..c7e92da05331a4e27b9fbbf52a9f8f879c20cec1 100644 (file)
@@ -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)
index 7bc8788647caf40767db011c39a3fe489ea04c15..78e43d70388c1d1e0a8c19251ac973476685d895 100644 (file)
@@ -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,
index fc4a3de7678fcbefc1ad74ffa41458dfea8640f7..527381222f8806509ffd580ea017895b2ee03919 100644 (file)
@@ -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.  */
index 1115e4c0a7af113e21eefb99fb04ca794470e68a..10a3a5388de76b1a7cb727ae7ce6935f565ac17d 100644 (file)
@@ -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
index e0a874788494ea9fe3821c22a9fa57e757588dfe..6dec085cb75df5a5d6a0d04d7dbafa5792a2164f 100644 (file)
@@ -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>