@@ -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 '***'.
@@ -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)) \
@@ -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
+
/*
*/
@@ -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.
@@ -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.
@@ -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 $@ $< \
@@ -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;
}
}
@@ -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, ...)
@@ -177,4 +177,13 @@ glibc {
default: 1048576
}
}
+
+ ubsan {
+ halt_on_errors {
+ type: INT_32
+ minval: 0
+ maxval: 1
+ default: 1
+ }
+ }
}
@@ -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)
{
new file mode 100644
@@ -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 ();
+}
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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)
new file mode 100644
@@ -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;
+ }
+}
new file mode 100644
@@ -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];
@@ -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");
@@ -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
@@ -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
new file mode 100644
@@ -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__ */
@@ -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. */
@@ -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
@@ -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);
@@ -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;
@@ -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);
}
@@ -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__); \
@@ -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;
@@ -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)
@@ -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)
@@ -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,
@@ -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. */
@@ -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
@@ -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>